home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume26 / ssh-1.7 / part02 < prev    next >
Encoding:
Text File  |  1993-04-15  |  60.8 KB  |  2,611 lines

  1. Newsgroups: comp.sources.unix
  2. From: Steve Baker (ice@judy.indstate.edu)
  3. Subject: v26i168: ssh - Steve's SHell (a small csh-like shell), V1.7, Part02/04
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: Steve Baker (ice@judy.indstate.edu)
  8. Posting-Number: Volume 26, Issue 168
  9. Archive-Name: ssh-1.7/part02
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 2 (of 4)."
  18. # Contents:  eval.c exe.c vars.c
  19. # Wrapped by vixie@gw.home.vix.com on Thu Apr 15 22:49:01 1993
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'eval.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'eval.c'\"
  23. else
  24. echo shar: Extracting \"'eval.c'\" \(13497 characters\)
  25. sed "s/^X//" >'eval.c' <<'END_OF_FILE'
  26. X/* $Copyright:    $
  27. X * Copyright (c) 1991,1992,1993 by Steve Baker
  28. X * All rights reserved
  29. X *  
  30. X * This software is provided as is without any express or implied
  31. X * warranties, including, without limitation, the implied warranties
  32. X * of merchantability and fitness for a particular purpose.
  33. X */
  34. X#include "shell.h"
  35. X
  36. X#define T_EOL        0
  37. X#define T_OR        1
  38. X#define T_AND        2
  39. X
  40. X#define T_NOT        3
  41. X
  42. X#define T_EQ        5
  43. X#define T_NE        6
  44. X#define T_GE        7
  45. X#define T_GT        8
  46. X#define T_LE        9
  47. X#define T_LT        10
  48. X#define T_TEQ        11
  49. X#define T_TNE        12
  50. X
  51. X#define T_STR        15
  52. X#define T_NUM        16
  53. X#define T_SVAR        17
  54. X#define T_NVAR        18
  55. X
  56. X#define T_OP        20
  57. X#define T_CP        21
  58. X#define T_PLUS        25
  59. X#define T_MINUS        26
  60. X#define T_DIV        27
  61. X#define T_MUL        28
  62. X#define T_MOD        29
  63. X
  64. X#define T_PP        30
  65. X#define T_MM        31
  66. X#define T_LAND        32
  67. X#define T_LOR        33
  68. X#define T_TILD        34
  69. X
  70. X#define T_EXSIST    35
  71. X#define T_READ        36
  72. X#define T_WRITE        37
  73. X#define T_EXECUTE    38
  74. X#define T_OWNER        39
  75. X#define T_ZERO        40
  76. X#define T_PLAIN        41
  77. X#define T_DIR        42
  78. X#define T_SIZE        43
  79. X#define T_USER        44
  80. X#define T_GROUP        45
  81. X#define T_PROT        46
  82. X#define T_MODE        47
  83. X
  84. X#define T_SHL        50
  85. X#define T_SHR        51
  86. X#define T_XOR        52
  87. X
  88. X#define T_ERR        55
  89. X
  90. struct tlist {
  91. X  union _v {
  92. X    char *str;
  93. X    long num;
  94. X    struct _setvar *var;
  95. X  } v;
  96. X  short vp;
  97. X  char tok;
  98. X} *tlst;
  99. static char *exp;
  100. static long num, lp;
  101. static short vp;
  102. static char *str;
  103. struct _setvar *_set, *getvalidset();
  104. extern int err;
  105. X
  106. long expr(), eval(), doconditionals(), domath();
  107. long domuldiv(), dounary(), doprimary();
  108. char *getvalidenv();
  109. X
  110. long expr(wrd)
  111. char *wrd;
  112. X{
  113. X  int nt,tp,tok;
  114. X  long res;
  115. X  struct tlist *tsav;
  116. X  char *sav;
  117. X
  118. X/* hack to save previous value of exp and tlst to make expr() re-intrant */
  119. X  sav = exp;
  120. X  tsav = tlst;
  121. X  exp = wrd;
  122. X  err = tp = 0;
  123. X  tlst = (struct tlist *)calloc(nt=5,sizeof(struct tlist));
  124. X
  125. X  while(tok = get_next(exp)) {
  126. X    if (tp == nt) tlst = (struct tlist *)realloc(tlst,sizeof(struct tlist) * (nt+=5));
  127. X    tlst[tp].tok = tok;
  128. X    switch(tok) {
  129. X      case T_STR:
  130. X    tlst[tp].v.str = str;
  131. X    break;
  132. X      case T_NUM:
  133. X    tlst[tp].v.num = num;
  134. X    break;
  135. X      case T_SVAR:
  136. X    tlst[tp].vp = vp;
  137. X      case T_NVAR:
  138. X    tlst[tp].v.var = _set;
  139. X    break;
  140. X    }
  141. X    tp++;
  142. X  }
  143. X  if (tp == nt) tlst = (struct tlist *)realloc(tlst,sizeof(struct tlist) * ++nt);
  144. X  tlst[tp].tok = T_EOL;
  145. X  lp = 0;
  146. X  res = eval();
  147. X  if (!err && tlst[lp].tok == T_CP) error(3);
  148. X  else if (!err && tlst[lp].tok != T_EOL) error(1);
  149. X  for(tp=0;tlst[tp].tok;tp++)
  150. X    if (tlst[tp].tok == T_STR) free(tlst[tp].v.str);
  151. X  free(tlst);
  152. X  exp = sav;
  153. X  tlst = tsav;
  154. X  return err? 0 : res;
  155. X}
  156. X
  157. long eval()
  158. X{
  159. X  int res,res2;
  160. X
  161. X  res = doconditionals();
  162. X  if (err) return 0;
  163. X
  164. X  switch(tlst[lp++].tok) {
  165. X    case T_OR:
  166. X      res2 = eval();
  167. X      res = res || res2;
  168. X      break;
  169. X    case T_AND:
  170. X      res2 = eval();
  171. X      res = res && res2;
  172. X      break;
  173. X    case T_EOL:
  174. X      lp--;
  175. X      return res;
  176. X    case T_CP:
  177. X      lp--;
  178. X      return res;
  179. X    default:
  180. X      error(2);
  181. X      break;
  182. X  }
  183. X  return res;
  184. X}
  185. X
  186. long doconditionals()
  187. X{
  188. X  int ans;
  189. X
  190. X  if (tlst[lp].tok == T_STR || tlst[lp].tok == T_SVAR) return dostrcmp();
  191. X  ans = domath();
  192. X  if (err) return 0;
  193. X
  194. X  switch(tlst[lp++].tok) {
  195. X    case T_EQ:
  196. X      ans = ans == doconditionals();
  197. X      break;
  198. X    case T_NE:
  199. X      ans = ans != doconditionals();
  200. X      break;
  201. X    case T_GE:
  202. X      ans = ans >= doconditionals();
  203. X      break;
  204. X    case T_LE:
  205. X      ans = ans <= doconditionals();
  206. X      break;
  207. X    case T_GT:
  208. X      ans = ans > doconditionals();
  209. X      break;
  210. X    case T_LT:
  211. X      ans = ans < doconditionals();
  212. X      break;
  213. X    default:
  214. X      lp--;
  215. X      return ans;
  216. X  }
  217. X  return ans;
  218. X}
  219. X
  220. long domath()
  221. X{
  222. X  int res;
  223. X
  224. X  res = domuldiv();
  225. X  if (err) return 0;
  226. X
  227. X  switch(tlst[lp++].tok) {
  228. X    case T_PLUS:
  229. X      res += domath();
  230. X      break;
  231. X    case T_MINUS:
  232. X      res -= domath();
  233. X      break;
  234. X    case T_LAND:
  235. X      res &= domath();
  236. X      break;
  237. X    case T_LOR:
  238. X      res |= domath();
  239. X      break;
  240. X    case T_SHL:
  241. X      res <<= domath();
  242. X      break;
  243. X    case T_SHR:
  244. X      res >>= domath();
  245. X      break;
  246. X    case T_XOR:
  247. X      res ^= domath();
  248. X      break;
  249. X    default:
  250. X      lp--;
  251. X      return res;
  252. X  }
  253. X  return res;
  254. X}
  255. X
  256. long domuldiv()
  257. X{
  258. X  int res;
  259. X
  260. X  res = dounary();
  261. X  if (err) return 0;
  262. X
  263. X  switch(tlst[lp++].tok) {
  264. X    case T_MUL:
  265. X      res *= domuldiv();
  266. X      break;
  267. X    case T_DIV:
  268. X      res /= domuldiv();
  269. X      break;
  270. X    case T_MOD:
  271. X      res %= domuldiv();
  272. X      break;
  273. X    default:
  274. X      lp--;
  275. X      return res;
  276. X  }
  277. X  return res;
  278. X}
  279. X
  280. long dounary()
  281. X{
  282. X  int res, tok;
  283. X  char *fil = NULL;
  284. X  struct stat buf;
  285. X
  286. X  if (err) return 0;
  287. X  tok = tlst[lp++].tok;
  288. X  if (tok >= T_EXSIST && tok <= T_MODE) {
  289. X    if (tlst[lp].tok == T_STR) {
  290. X      fil = tlst[lp++].v.str;
  291. X    } else if (tlst[lp].tok == T_SVAR) {
  292. X      fil = tlst[lp].v.var->sv.wrd[tlst[lp].vp];
  293. X      lp++;
  294. X    } else {
  295. X      error(7);
  296. X      return 0;
  297. X    }
  298. X    if ((tok >= T_OWNER) && (stat(fil,&buf) < 0)) fil = NULL;
  299. X  }
  300. X
  301. X  switch(tok) {
  302. X    case T_MINUS:
  303. X      res = -dounary();
  304. X      break;
  305. X    case T_NOT:
  306. X      res = !dounary();
  307. X      break;
  308. X    case T_TILD:
  309. X      res = ~dounary();
  310. X      break;
  311. X    case T_PLUS:
  312. X      res = dounary();
  313. X      break;
  314. X    case T_MM:
  315. X    case T_PP:
  316. X      if (tlst[lp].tok != T_NVAR) {
  317. X        error(8);
  318. X    break;
  319. X      }
  320. X      if (!tlst[lp-1].v.var->protect) {
  321. X        if (tok == T_PP) tlst[lp].v.var->sv.val++;
  322. X        else tlst[lp].v.var->sv.val--;
  323. X      }
  324. X      res = dounary();
  325. X      break;
  326. X    case T_EXSIST:
  327. X      if (!fil) return res = 0;
  328. X      res = access(fil,F_OK)? 0 : 1;
  329. X      break;
  330. X    case T_READ:
  331. X      if (!fil) return res = 0;
  332. X      res = access(fil,R_OK)? 0 : 1;
  333. X      break;
  334. X    case T_WRITE:
  335. X      if (!fil) return res = 0;
  336. X      res = access(fil,W_OK)? 0 : 1;
  337. X      break;
  338. X    case T_EXECUTE:
  339. X      if (!fil) return res = 0;
  340. X      res = access(fil,X_OK)? 0 : 1;
  341. X      break;
  342. X    case T_OWNER:
  343. X      if (!fil) return res = 0;
  344. X      res = (buf.st_uid == getuid()? 1 : 0);
  345. X      break;
  346. X    case T_ZERO:
  347. X      if (!fil) return res = 0;
  348. X      res = (buf.st_size == 0? 1 : 0);
  349. X      break;
  350. X    case T_SIZE:
  351. X      if (!fil) return res = 0;
  352. X      res = buf.st_size;
  353. X      break;
  354. X    case T_PLAIN:
  355. X      if (!fil) return res = 0;
  356. X      res = (buf.st_mode & S_IFMT) == S_IFREG? 1 : 0;
  357. X      break;
  358. X    case T_DIR:
  359. X      if (!fil) return res = 0;
  360. X      res = (buf.st_mode & S_IFMT) == S_IFDIR? 1 : 0;
  361. X      break;
  362. X    case T_USER:
  363. X      if (!fil) return res = -1;
  364. X      res = buf.st_uid;
  365. X      break;
  366. X    case T_GROUP:
  367. X      if (!fil) return res = -1;
  368. X      res = buf.st_gid;
  369. X      break;
  370. X    case T_PROT:
  371. X      if (!fil) return res = 0;
  372. X      res = buf.st_mode & 0777;
  373. X      break;
  374. X    case T_MODE:
  375. X      if (!fil) return res = 0;
  376. X      res = buf.st_mode;
  377. X      break;
  378. X    default:
  379. X      lp--;
  380. X      res = doprimary();
  381. X  }
  382. X  return res;
  383. X}
  384. X
  385. long doprimary()
  386. X{
  387. X  long res;
  388. X  int tok;
  389. X
  390. X  if (tlst[lp++].tok == T_OP) {
  391. X    res = eval();
  392. X    if (tlst[lp].tok != T_CP) error(3);
  393. X    lp++;
  394. X    return res;
  395. X  }
  396. X  switch(tlst[--lp].tok) {
  397. X    case T_NUM:
  398. X      return tlst[lp++].v.num;
  399. X    case T_NVAR:
  400. X      res = tlst[lp++].v.var->sv.val;
  401. X      tok = tlst[lp].tok;
  402. X      if (tok == T_PP || tok == T_MM) {
  403. X        if (!tlst[lp-1].v.var->protect) {
  404. X      if (tok == T_PP) tlst[lp-1].v.var->sv.val++;
  405. X      else tlst[lp-1].v.var->sv.val--;
  406. X    }
  407. X        lp++;
  408. X      }
  409. X      return res;
  410. X    case T_SVAR:
  411. X    case T_STR:
  412. X      error(4);
  413. X      break;
  414. X    case T_EOL:
  415. X      error(5);
  416. X      break;
  417. X    case T_ERR:
  418. X      error(6);
  419. X      break;
  420. X    default:
  421. X      error(7);
  422. X      break;
  423. X  }
  424. X  return 0;
  425. X}
  426. X
  427. dostrcmp()
  428. X{
  429. X  int ans,tok;
  430. X  char *s, *s2;
  431. X
  432. X  if (tlst[lp].tok == T_STR) s = tlst[lp++].v.str;
  433. X  else {
  434. X    s = tlst[lp].v.var->sv.wrd[tlst[lp].vp];
  435. X    lp++;
  436. X  }
  437. X
  438. X  tok = tlst[lp++].tok;
  439. X  if (tok < T_EQ || tok > T_TNE) return 1;
  440. X  if (tlst[lp].tok != T_STR && tlst[lp].tok != T_SVAR) {
  441. X    error(7);
  442. X    return 0;
  443. X  }
  444. X  if (tlst[lp].tok == T_STR) s2 = tlst[lp++].v.str;
  445. X  else {
  446. X    s2 = tlst[lp].v.var->sv.wrd[tlst[lp].vp];
  447. X    lp++;
  448. X  }
  449. X  switch(tok) {
  450. X    case T_TEQ:
  451. X      ans = patmatch(s,s2);
  452. X      break;
  453. X    case T_TNE:
  454. X      ans = !patmatch(s,s2);
  455. X      break;
  456. X    case T_EQ:
  457. X      ans = !strcmp(s,s2);
  458. X      break;
  459. X    case T_NE:
  460. X      ans = strcmp(s,s2);
  461. X      break;
  462. X    case T_GE:
  463. X      ans = strcmp(s,s2) >= 0;
  464. X      break;
  465. X    case T_LE:
  466. X      ans = strcmp(s,s2) <= 0;
  467. X      break;
  468. X    case T_GT:
  469. X      ans = strcmp(s,s2) > 0;
  470. X      break;
  471. X    case T_LT:
  472. X      ans = strcmp(s,s2) < 0;
  473. X      break;
  474. X  }
  475. X  return ans;
  476. X}
  477. X
  478. X
  479. error(n)
  480. int n;
  481. X{
  482. X  switch(n) {
  483. X    case 1:
  484. X    case 2:
  485. X      fprintf(stderr,"End of expression expected.\n");
  486. X      break;
  487. X    case 3:
  488. X      fprintf(stderr,"Mismatched parentheses.\n");
  489. X      break;
  490. X    case 4:
  491. X      fprintf(stderr,"String found when numeric expected.\n");
  492. X      break;
  493. X    case 5:
  494. X      fprintf(stderr,"Unexpected end of expression.\n");
  495. X      break;
  496. X    case 6:
  497. X      fprintf(stderr,"Illegal character.\n");
  498. X      break;
  499. X    case 7:
  500. X      fprintf(stderr,"String literal expected.\n");
  501. X      break;
  502. X    case 8:
  503. X      fprintf(stderr,"Variable expected for ++ or --.\n");
  504. X      break;
  505. X  }
  506. X  err = 1;
  507. X}
  508. X
  509. X
  510. get_next()
  511. X{
  512. X  int i,pos;
  513. X  char *s, *t, c;
  514. X  static char numbuf[33];
  515. X
  516. X  while(isspace(*exp)) exp++;
  517. X  switch(*exp++) {
  518. X    case '+':
  519. X      if (*exp == '+') {
  520. X        exp++;
  521. X    return T_PP;
  522. X      }
  523. X      return T_PLUS;
  524. X    case '-':
  525. X      switch(*exp++) {
  526. X    case 'e':
  527. X      return T_EXSIST;
  528. X    case 'r':
  529. X      return T_READ;
  530. X    case 'w':
  531. X      return T_WRITE;
  532. X    case 'x':
  533. X      return T_EXECUTE;
  534. X    case 'o':
  535. X      return T_OWNER;
  536. X    case 'z':
  537. X      return T_ZERO;
  538. X    case 'f':
  539. X      return T_PLAIN;
  540. X    case 'd':
  541. X      return T_DIR;
  542. X    case 's':
  543. X      return T_SIZE;
  544. X    case 'u':
  545. X      return T_USER;
  546. X    case 'g':
  547. X      return T_GROUP;
  548. X    case 'p':
  549. X      return T_PROT;
  550. X    case 'm':
  551. X      return T_MODE;
  552. X    case '-':
  553. X      return T_MM;
  554. X      }
  555. X      exp--;
  556. X      return T_MINUS;
  557. X    case '/':
  558. X      return T_DIV;
  559. X    case '*':
  560. X      return T_MUL;
  561. X    case '%':
  562. X      return T_MOD;
  563. X    case '|':
  564. X      if (*exp != '|') return T_LOR;
  565. X      exp++;
  566. X      return T_OR;
  567. X    case '&':
  568. X      if (*exp != '&') return T_LAND;
  569. X      exp++;
  570. X      return T_AND;
  571. X    case '^':
  572. X      return T_XOR;
  573. X    case '~':
  574. X      return T_TILD;
  575. X    case '<':
  576. X      if (*exp == '<') {
  577. X    exp++;
  578. X    return T_SHL;
  579. X      }
  580. X      if (*exp == '=') {
  581. X    exp++;
  582. X    return T_LE;
  583. X      }
  584. X      return T_LT;
  585. X    case '>':
  586. X      if (*exp == '>') {
  587. X    exp++;
  588. X    return T_SHR;
  589. X      }
  590. X      if (*exp == '=') {
  591. X    exp++;
  592. X    return T_GE;
  593. X      }
  594. X      return T_GT;
  595. X    case '=':
  596. X      if (*exp == '~') {
  597. X        exp++;
  598. X    return T_TEQ;
  599. X      }
  600. X      if (*exp++ != '=') return T_ERR;
  601. X      return T_EQ;
  602. X    case '!':
  603. X      if (*exp == '=') {
  604. X        exp++;
  605. X    return T_NE;
  606. X      }
  607. X      if (*exp == '~') {
  608. X    exp++;
  609. X    return T_TNE;
  610. X      }
  611. X      return T_NOT;
  612. X    case 0:
  613. X      return T_EOL;
  614. X    case '(':
  615. X      return T_OP;
  616. X    case ')':
  617. X      return T_CP;
  618. X    case '$':
  619. X      if (*exp == '$') {
  620. X    exp++;
  621. X    if (*exp == '?') {
  622. X      exp++;
  623. X      s = getvalidenv(&exp,&pos);
  624. X      if (s) {
  625. X        num = 1;
  626. X        free(s);
  627. X      } else num = 0;
  628. X      return T_NUM;
  629. X    }
  630. X    if (*exp == '#') {
  631. X      exp++;
  632. X      s = getvalidenv(&exp,&pos);
  633. X      if (s) {
  634. X        if (pos < 0) {
  635. X          for(num=1,i=0;s[i];i++) if (s[i] == ':') num++;
  636. X        } else num = strlen(s);
  637. X        free(s);
  638. X      } else num = 0;
  639. X      return T_NUM;
  640. X    }
  641. X    s = getvalidenv(&exp,&pos);
  642. X    str = s;
  643. X    return T_STR;
  644. X      }
  645. X      if (*exp == '?') {
  646. X        exp++;
  647. X    if (getvalidset(&exp,&pos)) num = 1;
  648. X    else num = 0;
  649. X    return T_NUM;
  650. X      }
  651. X      if (*exp == '#') {
  652. X    exp++;
  653. X    if (_set = getvalidset(&exp,&pos)) {
  654. X      if (pos < 0) num = _set->nwrds;
  655. X      else num = strlen(_set->sv.wrd[pos]);
  656. X    } else num = 0;
  657. X    return T_NUM;
  658. X      }
  659. X      if (!(_set = getvalidset(&exp,&pos))) return T_ERR;
  660. X      if (_set->type != T_STRING) return T_NVAR;
  661. X      vp = pos < 0? 0 : pos;
  662. X      return T_SVAR;
  663. X      break;
  664. X    case '\'':
  665. X    case '"':
  666. X      c = *(exp-1);
  667. X      s = exp;
  668. X      while(*exp && *exp != c) {
  669. X        if (*exp == '\\') exp++;
  670. X    exp++;
  671. X      }
  672. X      t = (char *)malloc((exp-s)+1);
  673. X      for(i=0;s < exp;i++) t[i] = *s++;
  674. X      t[i] = 0;
  675. X      str = t;
  676. X      if (*exp == c) exp++;
  677. X      return T_STR;
  678. X    default:
  679. X      exp--;
  680. X      i = num = 0;
  681. X      if (isdigit(*exp)) {
  682. X    if (*exp == '0') {
  683. X      exp++;
  684. X      switch(*exp++) {
  685. X        case 'x':
  686. X        case 'X':
  687. X          while((isdigit(*exp) || (*exp >= 'a' && *exp <= 'f') || (*exp >= 'A' && *exp <= 'F')) && i < 8)
  688. X        numbuf[i++] = *exp++;
  689. X          if (!i || i > 8) return T_ERR;
  690. X          numbuf[i] = 0;
  691. X          for(i=0;numbuf[i];i++) {
  692. X        num <<= 4;
  693. X        num |= (isdigit(numbuf[i]) ? numbuf[i]-'0' : (islower(numbuf[i]) ? (numbuf[i] - 'a') + 10 : (numbuf[i] - 'A') + 10));
  694. X          }
  695. X          return T_NUM;
  696. X          break;
  697. X        case 'b':
  698. X        case 'B':
  699. X          while((*exp == '1' || *exp == '0') && i < 32) numbuf[i++] = *exp++;
  700. X          if (!i || i > 32) return T_ERR;
  701. X          numbuf[i] = 0;
  702. X          for(i=0;numbuf[i];i++) {
  703. X        num <<= 1;
  704. X        if (numbuf[i] == '1') num |= 1;
  705. X          }
  706. X          return T_NUM;
  707. X          break;
  708. X        default:
  709. X          exp--;
  710. X          while(*exp >= '0' && *exp < '8' && i < 10) numbuf[i++] = *exp++;
  711. X          if (!i) return T_NUM;
  712. X          if (i > 10) return T_ERR;
  713. X          numbuf[i] = 0;
  714. X          for (i=0;numbuf[i];i++) {
  715. X        num <<= 3;
  716. X        num |= numbuf[i] - '0';
  717. X          }
  718. X          return T_NUM;
  719. X          break;
  720. X      }
  721. X    }
  722. X        while(isdigit(*exp) && i < 11) numbuf[i++] = *exp++;
  723. X    if (i > 11) return T_ERR;
  724. X    numbuf[i] = 0;
  725. X    num = atoi(numbuf);
  726. X    return T_NUM;
  727. X      }
  728. X      s = exp;
  729. X      while(*exp && !isspace(*exp)) exp++;
  730. X      str = t = (char *)malloc((exp-s)+1);
  731. X      for(i=0;s<exp;i++) t[i] = *s++;
  732. X      t[i] = 0;
  733. X      return T_STR;
  734. X  }
  735. X  /*NOTREACHED*/
  736. X}
  737. END_OF_FILE
  738. if test 13497 -ne `wc -c <'eval.c'`; then
  739.     echo shar: \"'eval.c'\" unpacked with wrong size!
  740. fi
  741. # end of 'eval.c'
  742. fi
  743. if test -f 'exe.c' -a "${1}" != "-c" ; then 
  744.   echo shar: Will not clobber existing file \"'exe.c'\"
  745. else
  746. echo shar: Extracting \"'exe.c'\" \(23142 characters\)
  747. sed "s/^X//" >'exe.c' <<'END_OF_FILE'
  748. X/* $Copyright:    $
  749. X * Copyright (c) 1991,1992,1993 by Steve Baker
  750. X * All rights reserved
  751. X *  
  752. X * This software is provided as is without any express or implied
  753. X * warranties, including, without limitation, the implied warranties
  754. X * of merchantability and fitness for a particular purpose.
  755. X */
  756. X
  757. X#include <errno.h>
  758. X#include <pwd.h>
  759. X#include "shell.h"
  760. X
  761. enum {
  762. X  T_WORD = 1, T_INPUT, T_OUTPUT, T_APP_OUTPUT, T_ERROR, T_APP_ERROR, T_BOTH,
  763. X  T_APP_BOTH, T_BAR, T_BAR_ERROR, T_BAR_BOTH, T_AMP, T_NOTTY, T_EOL,
  764. X  T_PINPUT, T_POUTPUT, T_PERROR, T_PBOTH, T_APINPUT, T_APP_POUTPUT,
  765. X  T_APP_PERROR, T_APP_PBOTH, T_AND, T_OR, T_SEMICOLON
  766. X};
  767. X
  768. X#define FDFLAG        -2
  769. X
  770. X/* ought to make a hash for this: */
  771. struct Token {
  772. X  char tok[5];
  773. X  char val;
  774. X} tokens[] = {
  775. X  "&", T_AMP,
  776. X  "&!", T_NOTTY,
  777. X  "&&", T_AND,
  778. X  ";", T_SEMICOLON,
  779. X  "<", T_INPUT,
  780. X  "<%", T_PINPUT,
  781. X  "<<%", T_APINPUT,
  782. X  ">", T_OUTPUT,
  783. X  ">!", T_ERROR,
  784. X  ">!%", T_PERROR,
  785. X  ">%", T_POUTPUT,
  786. X  ">&", T_BOTH,
  787. X  ">&%", T_PBOTH,
  788. X  ">>", T_APP_OUTPUT,
  789. X  ">>!", T_APP_ERROR,
  790. X  ">>!%", T_APP_PERROR,
  791. X  ">>%", T_APP_POUTPUT,
  792. X  ">>&", T_APP_BOTH,
  793. X  ">>&%", T_APP_PBOTH,
  794. X  "|", T_BAR,
  795. X  "|!", T_BAR_ERROR,
  796. X  "|&", T_BAR_BOTH,
  797. X  "||", T_OR
  798. X};
  799. X
  800. X#define N_TOKENS    22
  801. X
  802. int ptr, lvl;
  803. char **wrds;
  804. X
  805. extern char buf[1025],path[1025];
  806. extern char **PATH, _loginshell, _inpipe, _echo;
  807. extern char _nofork, _noclobber, _nohup, _nobgnull;
  808. extern int max_ent, errno, _pgrp, _status, _failat;
  809. extern unsigned long SIGMASK;
  810. extern struct proc_tab *proc;
  811. extern struct _FILES FILES[MAX_FILES];
  812. X
  813. char *getnext();
  814. void check_children(), *malloc();
  815. X
  816. X/*
  817. X * Setup all the pointers and global variables for the getnext() routine
  818. X * and call check which will parse and send the resulting commands to
  819. X * invoke().
  820. X */
  821. XEXEC(cmd)
  822. char **cmd;
  823. X{
  824. X  int pid;
  825. X
  826. X  if (!cmd[0]) return 0;
  827. X  wrds = cmd;
  828. X  lvl = ptr = 0;
  829. X  if (check(&pid,FALSE,NULL) < 0) _status = 1;
  830. X  pwait();
  831. X  return pid;
  832. X}
  833. X
  834. X/*
  835. X * This here is a recursive routine to evaluate the above defined tokens
  836. X * and to finally invoke the executor to execute the command (execute is
  837. X * the right word for it alright).  This routine traverses a pipe to the
  838. X * last command in the pipe and starts invoking the commands in revearse
  839. X * order, right to left.  Pipe descriptors are magically kept track of and
  840. X * cleaned up.  This routine also sets up file redirections for redirect
  841. X * and sh_redirect (for builtins) and removes all the tokens (and redirected
  842. X * file names) from the command line. Any remaining ;'s are parsed here as
  843. X * well as `&&' and `||'.
  844. X */
  845. check(wpid,imapipe,piped)
  846. char imapipe;
  847. int *wpid, *piped;
  848. X{
  849. X  int token, tok, pid;
  850. X  int i= 0, in = 0, out = 1, err = 2, pd[2];
  851. X  char **tmp = NULL, *word = NULL, *inf = NULL, *outf = NULL, *errf = NULL;
  852. X  char f, bg = FALSE, outa = FALSE, erra = FALSE;
  853. X
  854. X  tmp = (char **)calloc(5,sizeof(char *));
  855. X  while(1) {
  856. X    word = getnext(&token);
  857. X    switch(token) {
  858. X      case T_WORD:
  859. X    tmp[i++] = word;
  860. X    if (!(i % 5)) tmp = (char **)realloc(tmp,sizeof(char *) * (i+5));
  861. X    tmp[i] = NULL;
  862. X    continue;
  863. X      case T_INPUT:
  864. X      case T_PINPUT:
  865. X      case T_APINPUT:
  866. X    if (imapipe) {
  867. X      free_stuff(tmp,in,inf,out,outf,err,errf);
  868. X      fprintf(stderr,"Ambigous redirection.\n");
  869. X      return -1;
  870. X    }
  871. X    if (in != 0) {
  872. X      free_stuff(tmp,in,inf,out,outf,err,errf);
  873. X      fprintf(stderr,"Extra < or <%.\n");
  874. X      return -1;
  875. X    }
  876. X    inf = getnext(&tok);
  877. X    if (tok != T_WORD) {
  878. X      free_stuff(tmp,in,inf,out,outf,err,errf);
  879. X      fprintf(stderr,"Invalid input redirection.\n");
  880. X      return -1;
  881. X    }
  882. X    if (token != T_INPUT) {
  883. X      if ((in = makepipe(inf,0,(token==T_APINPUT))) < 0) {
  884. X        free_stuff(tmp,in,inf,out,outf,err,errf);
  885. X        return -1;
  886. X      }
  887. X    } else in = FDFLAG;
  888. X    continue;
  889. X      case T_OUTPUT:
  890. X      case T_POUTPUT:
  891. X      case T_APP_OUTPUT:
  892. X      case T_APP_POUTPUT:
  893. X    if (out != 1) {
  894. X      free_stuff(tmp,in,inf,out,outf,err,errf);
  895. X      fprintf(stderr,"Extra >, >> or >%.\n");
  896. X      return -1;
  897. X    }
  898. X    outf = getnext(&tok);
  899. X    if (tok != T_WORD) {
  900. X      free_stuff(tmp,in,inf,out,outf,err,errf);
  901. X      fprintf(stderr,"Invalid output redirection\n");
  902. X      return -1;
  903. X    }
  904. X    if (token == T_POUTPUT || token == T_APP_POUTPUT) {
  905. X      if ((out = makepipe(outf,1,token==T_APP_POUTPUT)) < 0) {
  906. X        free_stuff(tmp,in,inf,out,outf,err,errf);
  907. X        return -1;
  908. X      }
  909. X    } else out = FDFLAG;
  910. X    outa = (token == T_APP_OUTPUT);
  911. X    if (_noclobber && out == FDFLAG) {
  912. X      f = access(outf,F_OK);
  913. X      if (outa) {
  914. X        if (f) {
  915. X          free_stuff(tmp,in,inf,out,outf,err,errf);
  916. X          fprintf(stderr,"Output redirection would create a new file.\n");
  917. X          return -1;
  918. X        }
  919. X      } else {
  920. X        if (!f) {
  921. X          free_stuff(tmp,in,inf,out,outf,err,errf);
  922. X          fprintf(stderr,"Output redirection would overwrite file.\n");
  923. X          return -1;
  924. X        }
  925. X      }
  926. X    }
  927. X    continue;
  928. X      case T_ERROR:
  929. X      case T_PERROR:
  930. X      case T_APP_ERROR:
  931. X      case T_APP_PERROR:
  932. X    if (err != 2) {
  933. X      free_stuff(tmp,in,inf,out,outf,err,errf);
  934. X      fprintf(stderr,"extra >!, >!% or >>!\n");
  935. X      return -1;
  936. X    }
  937. X    errf = getnext(&tok);
  938. X    if (tok != T_WORD) {
  939. X      free_stuff(tmp,in,inf,out,outf,err,errf);
  940. X      fprintf(stderr,"invalid output redirection\n");
  941. X      return -1;
  942. X    }
  943. X    if (token == T_PERROR || token == T_APP_PERROR) {
  944. X      if ((err = makepipe(errf,2,token==T_APP_PERROR)) < 0) {
  945. X        free_stuff(tmp,in,inf,out,outf,err,errf);
  946. X        return -1;
  947. X      }
  948. X    } else err = FDFLAG;
  949. X    erra = (token == T_APP_ERROR);
  950. X    if (_noclobber && err == FDFLAG) {
  951. X      f = access(errf,F_OK);
  952. X      if (erra) {
  953. X        if (f) {
  954. X          free_stuff(tmp,in,inf,out,outf,err,errf);
  955. X          fprintf(stderr,"output redirection would create a new file.\n");
  956. X          return -1;
  957. X        }
  958. X      } else {
  959. X        if (!f) {
  960. X          free_stuff(tmp,in,inf,out,outf,err,errf);
  961. X          fprintf(stderr,"output redirection would overwrite file.\n");
  962. X          return -1;
  963. X        }
  964. X      }
  965. X    }
  966. X    continue;
  967. X      case T_BOTH:
  968. X      case T_PBOTH:
  969. X      case T_APP_BOTH:
  970. X      case T_APP_PBOTH:
  971. X    if (out != 1) {
  972. X      free_stuff(tmp,in,inf,out,outf,err,errf);
  973. X      fprintf(stderr,"extra >, >% or >>\n");
  974. X      return -1;
  975. X    }
  976. X    if (err != 2) {
  977. X      free_stuff(tmp,in,inf,out,outf,err,errf);
  978. X      fprintf(stderr,"extra >!, >!% or >>!\n");
  979. X      return -1;
  980. X    }
  981. X    outf = getnext(&tok);
  982. X    if (tok != T_WORD) {
  983. X      free_stuff(tmp,in,inf,out,outf,err,errf);
  984. X      fprintf(stderr,"invalid output redirection\n");
  985. X      return -1;
  986. X    }
  987. X    if (token == T_PBOTH || token == T_APP_PBOTH) {
  988. X      if ((err = out = makepipe(outf,3,token==T_APP_PBOTH)) < 0) {
  989. X        free_stuff(tmp,in,inf,out,outf,err,errf);
  990. X        return -1;
  991. X      }
  992. X    } else err = out = FDFLAG;
  993. X    errf = outf;
  994. X    erra = outa = (token == T_APP_BOTH);
  995. X    if (_noclobber && out == FDFLAG) {
  996. X      f = access(outf,F_OK);
  997. X      if (outa) {
  998. X        if (f) {
  999. X          free_stuff(tmp,in,inf,out,outf,err,errf);
  1000. X          fprintf(stderr,"output redirection would create a new file.\n");
  1001. X          return -1;
  1002. X        }
  1003. X      } else {
  1004. X        if (!f) {
  1005. X          free_stuff(tmp,in,inf,out,outf,err,errf);
  1006. X          fprintf(stderr,"output redirection would overwrite file.\n");
  1007. X          return -1;
  1008. X        }
  1009. X      }
  1010. X    }
  1011. X    continue;
  1012. X      case T_BAR:
  1013. X      case T_BAR_ERROR:
  1014. X      case T_BAR_BOTH:
  1015. X      case T_AMP:
  1016. X      case T_NOTTY:
  1017. X      case T_EOL:
  1018. X    tmp[i] = NULL;
  1019. X    if (token == T_BAR) {
  1020. X      if (out != 1) {
  1021. X        free_stuff(tmp,in,inf,out,outf,err,errf);
  1022. X        fprintf(stderr,">, >% or >> conflicts with |\n");
  1023. X        return -1;
  1024. X      }
  1025. X      if ((bg = check(wpid,TRUE,&out)) < 0) return bg;
  1026. X    }
  1027. X    if (token == T_BAR_ERROR) {
  1028. X      if (err != 2) {
  1029. X        free_stuff(tmp,in,inf,out,outf,err,errf);
  1030. X        fprintf(stderr,">!, >!% or >>! conflicts with |!\n");
  1031. X        return -1;
  1032. X      }
  1033. X      if ((bg = check(wpid,TRUE,&err)) < 0) return bg;
  1034. X    }
  1035. X    if (token == T_BAR_BOTH) {
  1036. X      if (out != 1) {
  1037. X        free_stuff(tmp,in,inf,out,outf,err,errf);
  1038. X        fprintf(stderr,">, >% or >> conflicts with |&\n");
  1039. X        return -1;
  1040. X      }
  1041. X      if (err != 2) {
  1042. X        free_stuff(tmp,in,inf,out,outf,err,errf);
  1043. X        fprintf(stderr,">!, >!% or >>! conflicts with |&\n");
  1044. X        return -1;
  1045. X      }
  1046. X      if ((bg = check(wpid,TRUE,&out)) < 0) return bg;
  1047. X      err = out;
  1048. X    }
  1049. X    if (imapipe) {
  1050. X      if (pipe(pd) < 0) {
  1051. X        free_stuff(tmp,in,inf,out,outf,err,errf);
  1052. X        fprintf(stderr,"error creating pipe.\n");
  1053. X        return -1;
  1054. X      }
  1055. X      *piped = pd[1];
  1056. X      in = pd[0];
  1057. X    }
  1058. X    if (token == T_AMP) bg = 1;
  1059. X    if (token == T_NOTTY) bg = 2;
  1060. X    if ((pid = invoke(tmp,in,inf,out,outf,outa,err,errf,erra,bg)) < 0) _status = 1;
  1061. X    *wpid = pid;
  1062. X    free_stuff(tmp,in,inf,out,outf,err,errf);
  1063. X    return bg;
  1064. X      case T_AND:
  1065. X      case T_OR:
  1066. X      case T_SEMICOLON:
  1067. X    tmp[i] = NULL;
  1068. X    if ((pid = invoke(tmp,in,inf,out,outf,outa,err,errf,erra,bg)) < 0) _status = 1;
  1069. X    *wpid = pid;
  1070. X    free_stuff(tmp,in,inf,out,outf,err,errf);
  1071. X    pwait();
  1072. X    if (token == T_OR && !_status) return 0;
  1073. X    if (token == T_AND && _status) return 0;
  1074. X    if (token == T_SEMICOLON && badstat(_status)) return 0;
  1075. X    tmp = (char **)calloc(5,sizeof(char *));
  1076. X    i = 0;
  1077. X    break;
  1078. X    }
  1079. X  }
  1080. X}
  1081. X
  1082. X/* Self explanitory. Used in the above routine */
  1083. free_stuff(tmp,in,inf,out,outf,err,errf)
  1084. char **tmp, *inf, *outf, *errf;
  1085. BYTE in, out, err;
  1086. X{
  1087. X  int i;
  1088. X
  1089. X  if (tmp) {
  1090. X    for(i=0;tmp[i];i++) free(tmp[i]);
  1091. X    free(tmp);
  1092. X  }
  1093. X  if (inf) free(inf);
  1094. X  if (outf) free(outf);
  1095. X  if (errf) free(errf);
  1096. X  if (in > 0) close(in);
  1097. X  if (out > 1) close(out);
  1098. X  if (err > 2) close(err);
  1099. X}
  1100. X
  1101. X/*
  1102. X * Returns a valid file descritor or will make a pipe file descriptor
  1103. X * if necessary.  Normally if it is determined that we are dealing with
  1104. X * a pipe, we delete the reference that we are going to use from the
  1105. X * FILES information (whether it be the input or output side), unless
  1106. X * app is true (therefore a appended pipe reference).
  1107. X */
  1108. makepipe(name,d,app)
  1109. char *name, d, app;
  1110. X{
  1111. X  BYTE i, pd;
  1112. X  int p[2];
  1113. X
  1114. X  for(i=0;i<MAX_FILES;i++)
  1115. X    if (FILES[i].name && !strcmp(FILES[i].name,name)) break;
  1116. X
  1117. X  if (i == MAX_FILES) {
  1118. X    for(i=0;i<MAX_FILES;i++)
  1119. X      if (!FILES[i].name) break;
  1120. X    if (i == MAX_FILES) {
  1121. X      fprintf(stderr,"File descriptor table full.\n");
  1122. X      return -1;
  1123. X    }
  1124. X
  1125. X    FILES[i].name = SCOPY(name);
  1126. X    FILES[i].file = SCOPY("<PIPE>");
  1127. X    FILES[i].pread = FILES[i].pwrite = FALSE;
  1128. X    FILES[i].ispipe = FILES[i].read = FILES[i].write = TRUE;
  1129. X    pipe(p);
  1130. X    FILES[i].pipe = p[0];
  1131. X    FILES[i].desc = p[1];
  1132. X    fcntl(p[0],F_SETFD,1);
  1133. X    fcntl(p[1],F_SETFD,1);
  1134. X  }
  1135. X  if (FILES[i].ispipe) {
  1136. X    if (!d) {
  1137. X      if (FILES[i].read) {
  1138. X    if (FILES[i].write) {
  1139. X      pd = FILES[i].pipe;
  1140. X      if (!app) FILES[i].pipe = FILES[i].read = 0;
  1141. X    } else {
  1142. X      pd = FILES[i].desc;
  1143. X      if (!app) {
  1144. X        free(FILES[i].name);
  1145. X        free(FILES[i].file);
  1146. X        FILES[i].name = NULL;
  1147. X      }
  1148. X    }
  1149. X      } else {
  1150. X        fprintf(stderr,"Could not open descriptor %s for reading.\n",name);
  1151. X    return -1;
  1152. X      }
  1153. X    } else {
  1154. X      if (FILES[i].write) {
  1155. X    pd = FILES[i].desc;
  1156. X    if (!app) {
  1157. X      if (FILES[i].read) {
  1158. X        FILES[i].desc = FILES[i].pipe;
  1159. X        FILES[i].pipe = FILES[i].write = 0;
  1160. X      } else {
  1161. X        free(FILES[i].name);
  1162. X        free(FILES[i].file);
  1163. X        FILES[i].name = NULL;
  1164. X      }
  1165. X    }
  1166. X      } else {
  1167. X        fprintf(stderr,"Could not open descriptor %s for writing.\n",name);
  1168. X    return -1;
  1169. X      }
  1170. X    }
  1171. X    return pd;
  1172. X  }
  1173. X  if (d) FILES[i].pwrite = 1;
  1174. X  else FILES[i].pread = 1;
  1175. X  return FILES[i].desc;
  1176. X}
  1177. X
  1178. X/*
  1179. X * This gets the next token or word.  Try not to malloc anything until
  1180. X * we're sure we've got to.  Slightly recursive with respect to ()'s.
  1181. X * We remove the outer parens only, made recursive so something like:
  1182. X * secho ()()()() is handled correctly (all parens removed) and
  1183. X * secho (()()()()) removes only the outer parens.
  1184. X */
  1185. char *getnext(tok)
  1186. int *tok;
  1187. X{
  1188. X  char *wrd = NULL, st, end, n, m;
  1189. X
  1190. X  if (wrds[ptr] == NULL) {
  1191. X    *tok = T_EOL;
  1192. X    return NULL;
  1193. X  }
  1194. X
  1195. X  if (wrds[ptr][0] == '(' && !wrds[ptr][1]) {
  1196. X    if (!lvl++) {
  1197. X      ptr++;
  1198. X      return getnext(tok);
  1199. X    }
  1200. X  }
  1201. X
  1202. X  if (lvl && wrds[ptr][0] == ')' && !wrds[ptr][1]) {
  1203. X    if (!--lvl) {
  1204. X      ptr++;
  1205. X      return getnext(tok);
  1206. X    }
  1207. X  }
  1208. X
  1209. X  if (!lvl) {
  1210. X    st = 0;
  1211. X    end = N_TOKENS;
  1212. X    while(st <= end) {
  1213. X      m = (st+end)/2;
  1214. X      if (!(n = strcmp(tokens[m].tok,wrds[ptr]))) {
  1215. X    ptr++;
  1216. X    *tok = tokens[m].val;
  1217. X    return NULL;
  1218. X      } else if (n < 0) st = m+1;
  1219. X      else end = m-1;
  1220. X    }
  1221. X  }
  1222. X  
  1223. X/*
  1224. X * if it wasn't for this part here, we wouldn't need to malloc for check()
  1225. X * at all...
  1226. X */
  1227. X  if (!lvl && (wrds[ptr][0] == '"' || wrds[ptr][0] == '\'')) {
  1228. X    wrd = SCOPY(wrds[ptr]+1);
  1229. X    wrd[strlen(wrd)-1] = 0;
  1230. X  } else wrd = SCOPY(wrds[ptr]);
  1231. X  ptr++;
  1232. X  *tok = T_WORD;
  1233. X  return wrd;
  1234. X}
  1235. X
  1236. X/*
  1237. X * This is where we actually open up the files for the redirection.
  1238. X * Background jobs with no files to read or write try to get redirected to
  1239. X * /dev/null.
  1240. X *
  1241. X * This routine is called from the child process before the exec.
  1242. X */
  1243. redirect(in,inf,out,outf,outa,err,errf,erra,bg)
  1244. int in,out,err;
  1245. char *inf,*outf,*errf;
  1246. char outa,erra,bg;
  1247. X{
  1248. X  int i,flags;
  1249. X
  1250. X  if (in == 0 && bg && !_nobgnull) {
  1251. X    if (inf) free(inf);
  1252. X    inf = SCOPY(NULL_DEV);
  1253. X    in = FDFLAG;
  1254. X  }
  1255. X  if (in != 0) {
  1256. X    close(0);
  1257. X    if (in > 0) fcntl(in,F_DUPFD,0);
  1258. X    else if (open(inf,O_RDONLY) == -1) {
  1259. X      fprintf(stderr,"can't open %s for input\n",inf);
  1260. X      return -1;
  1261. X    }
  1262. X  }
  1263. X  if (out == 1 && bg && !_nobgnull) {
  1264. X    if (outf) free(outf);
  1265. X    outf = SCOPY(NULL_DEV);
  1266. X    out = FDFLAG;
  1267. X  }
  1268. X  if (err == 2 && bg && !_nobgnull) {
  1269. X    if (errf) free(errf);
  1270. X    if (!strcmp(outf,NULL_DEV)) errf = outf;
  1271. X    else errf = SCOPY(NULL_DEV);
  1272. X    err = FDFLAG;
  1273. X  }
  1274. X  if (out != 1) {
  1275. X    close(1);
  1276. X    if (out > 1) fcntl(out,F_DUPFD,1);
  1277. X    else {
  1278. X      flags = O_WRONLY | O_CREAT | (outa? O_APPEND : O_TRUNC);
  1279. X      if (open(outf,flags,0666) == -1) {
  1280. X    fprintf(stderr,"can't open %s for output\n",outf);
  1281. X    return -1;
  1282. X      }
  1283. X    }
  1284. X  }
  1285. X  if (err != 2) {
  1286. X    close(2);
  1287. X    if (err > 2) fcntl(err,F_DUPFD,2);
  1288. X    else {
  1289. X      if (errf == outf) dup(1);
  1290. X      else {
  1291. X    flags = O_WRONLY | O_CREAT | (erra? O_APPEND : O_TRUNC);
  1292. X    if (open(errf,flags,0666) == -1) {
  1293. X      fprintf(stderr,"can't open %s for output\n",errf);
  1294. X      return -1;
  1295. X    }
  1296. X      }
  1297. X    }
  1298. X  }
  1299. X  for(i=3;i<20;i++) close(i);
  1300. X  if (inf) free(inf);
  1301. X  if (outf) free(outf);
  1302. X  if (errf && errf != outf) free(errf);
  1303. X  return 0;
  1304. X}
  1305. X
  1306. X/*
  1307. X * Finally, this is where we get to do our fork and exec the command.
  1308. X * Not very pretty, but it works.
  1309. X */ 
  1310. invoke(arg,in,inf,out,outf,outa,err,errf,erra,bg)
  1311. char **arg,*inf,*outf,*errf;
  1312. int in,out,err;
  1313. char outa,erra,bg;
  1314. X{
  1315. X  unsigned long mask;
  1316. X  int pid,i,j = 0,ent;
  1317. X  struct stat lbuf;
  1318. X  static WORD lpid = 0;
  1319. X
  1320. X  if (_echo) {
  1321. X    for(i=0;arg[i];i++) {
  1322. X      if (i > 0) putchar(' ');
  1323. X      fputs(arg[i],stdout);
  1324. X    }
  1325. X    putchar('\n');
  1326. X  }
  1327. X
  1328. X/* check for built-ins */
  1329. X  if (parse_arg(arg,in,inf,out,outf,outa,err,errf,erra,bg) == SHELL_COMMAND) return 0;
  1330. X
  1331. X/*
  1332. X * Evaluate paths here.  This is where we run through our PATH var and prepend
  1333. X * paths to the command until we find where the command is and run it, if we
  1334. X * don't find our command, we'll fall through and see if it's a directory in
  1335. X * our current working directory.  If we have no PATH var then we'll at least
  1336. X * try our current working dir.  Also, if the command already has path info
  1337. X * in it, we'll leave it alone, assuming the user knows what he's doing.
  1338. X *
  1339. X * A hash table like csh has might be nice, but since most commands are
  1340. X * stored in only a few directories, for most people it might be a waste
  1341. X * of code and memory to do.
  1342. X */
  1343. X  if (index(arg[0],'/')) {
  1344. X    if (arg[0][0] != '/') sprintf(path,"./%s",arg[0]);
  1345. X    else strcpy(path,arg[0]);
  1346. X    if ((access(path,F_OK)) == 0)    /* I imagine this is not needed */
  1347. X      if (stat(path,&lbuf) > -1)    /* just use this */
  1348. X    if ((lbuf.st_mode & S_IFMT) == S_IFREG) j = 1;
  1349. X  } else {
  1350. X    for(i=0;PATH[i];i++) {
  1351. X      sprintf(path,"%s/%s",PATH[i],arg[0]);
  1352. X      if ((access(path,F_OK)) == 0)
  1353. X    if (stat(path,&lbuf) > -1)
  1354. X      if ((lbuf.st_mode & S_IFMT) == S_IFREG) { j = 1; break; }
  1355. X    }
  1356. X  }
  1357. X/*
  1358. X * Check if the command is a directory or not.  Only checked when we couldn't
  1359. X * find anything worth running in our path list. 
  1360. X */
  1361. X  if (j == 0) {
  1362. X    if (arg[1] == NULL && stat(arg[0],&lbuf) > -1) {
  1363. X      if (((lbuf.st_mode & S_IFMT) == S_IFDIR) || ((lbuf.st_mode & S_IFMT) == S_IFLNK)) {
  1364. X    auto_cd(arg[0]);
  1365. X    return 0;
  1366. X      }
  1367. X    }
  1368. X    fprintf(stderr,"%s: command not found.\n",arg[0]);
  1369. X    return -1;
  1370. X  }
  1371. X/* Check to see if we can actually run it! */
  1372. X  if (access(path,X_OK)) {
  1373. X    fprintf(stderr,"%s: permission denied.\n",arg[0]);
  1374. X    return -1;
  1375. X  }
  1376. X
  1377. X/*
  1378. X * Here we go.  Probably ought to try and use vfork, but I'm not too worried
  1379. X * about it.  Probably be better to keep it fork for portibility anyway.
  1380. X */
  1381. X  mask = sigblock(sigmask(SIGCHLD));
  1382. X
  1383. X  if (_nofork) pid = 0;
  1384. X  else pid = fork();
  1385. X
  1386. X  if (pid) {
  1387. X    if (pid < 0) {
  1388. X      if (errno == EAGAIN) {
  1389. X    fprintf(stderr,"%s: can't fork - process limit exceeded!\n",arg[0]);
  1390. X      } else fprintf(stderr,"%s: out of memory!\n",arg[0]);
  1391. X      _status = 2;
  1392. X      sigsetmask(mask);
  1393. X      return pid;
  1394. X    }
  1395. X/*
  1396. X * What a mess! Have to do this here so we keep track of lpid.
  1397. X * Ought to be some way to syncronize processes so that the parent gives
  1398. X * out the control terminal, before the child can exec.  Perhaps some kind
  1399. X * of semaphore locking mechanism?
  1400. X */
  1401. X    if (in > 0 && out < 2 && err < 3) lpid = pid;
  1402. X    else if (in < 1 && out < 2 && err < 3) lpid = 0;
  1403. X
  1404. X/* make our process table entry. */
  1405. X    ent = get_proc_ent();
  1406. X    proc[ent].pid = pid;
  1407. X    proc[ent].bg = bg;
  1408. X    proc[ent].cmd = (char *)strcpy(malloc(strlen(arg[0])+1),arg[0]);
  1409. X    proc[ent].pipe = lpid;
  1410. X
  1411. X    if (!bg && lpid) proc[ent].pgrp = lpid;
  1412. X    else if (!bg) proc[ent].pgrp = pid;
  1413. X    else proc[ent].pgrp = _pgrp;
  1414. X    proc[ent].status = STAT_RUNNING;
  1415. X
  1416. X/*
  1417. X * Dangerous, since a bg'ed process could gain control of the terminal
  1418. X * before we write this.  But if that happens we're screwed anyway
  1419. X * when it comes time to read from the terminal.
  1420. X */
  1421. X    if (bg == 1 && (!lpid || lpid == pid))
  1422. X      if (in > 0 || out > 1 || err > 2) printf(" [%d] (%d) %s\n",ent,pid,arg[0]);
  1423. X      else printf(" [%d] %d\n",ent,pid);
  1424. X
  1425. X    sigsetmask(mask);
  1426. X    return pid;
  1427. X  } else {
  1428. X    if (bg == 2) {    /* Void tty association if spawned w/ &! */
  1429. X      close(0); close(1); close(2);
  1430. X      if (fork()) exit(0);
  1431. X      setpgrp(0,0);
  1432. X      if ((i=open("/dev/tty",O_RDWR)) < 0) exit(1);
  1433. X      ioctl(i,TIOCNOTTY,0);
  1434. X      close(i);
  1435. X      if (fork()) exit(0);
  1436. X      if (fork()) exit(0);
  1437. X    }
  1438. X
  1439. X    pid = getpid();
  1440. X    if (in > 0 && out < 2 && err < 3) lpid = pid;
  1441. X    else if (in < 1 && out < 2 && err < 3) lpid = 0;
  1442. X
  1443. X/*
  1444. X * Gain control of the terminal if need be. Since there is no way to
  1445. X * adaquately perform process syncronization, it must be done here.
  1446. X * There has got to be a better way to do this... For crying out loud!
  1447. X */
  1448. X    signal(SIGTSTP,SIG_IGN);    /* Hokey signal ignore hack to keep  */
  1449. X    signal(SIGTTIN,SIG_IGN);    /* child from stopping when it tries */
  1450. X    signal(SIGTTOU,SIG_IGN);    /* to get control of the terminal.   */
  1451. X
  1452. X    if (!bg && lpid) setpgrp(pid,lpid);
  1453. X    else if (!bg) setpgrp(pid,pid);
  1454. X    if (!bg && (lpid == 0 || pid == lpid) && !_inpipe) tcsetpgrp(TTY,pid);
  1455. X
  1456. X/*
  1457. X * Redirect stuff if we can (otherwise exit), then turn signals back to
  1458. X * their default and ignore SIGHUP for background processes.
  1459. X * Then try to exec the command.
  1460. X */
  1461. X    if (redirect(in,inf,out,outf,outa,err,errf,erra,bg) < 0) exit(1);
  1462. X
  1463. X    for(i=1;i<32;i++) signal(i,SIG_DFL);
  1464. X    sigsetmask(0);
  1465. X    if (bg || _nohup) sigblock(sigmask(SIGHUP));
  1466. X
  1467. X    execv(path,arg);
  1468. X    switch(errno) {
  1469. X      case ENOENT:
  1470. X    fprintf(stderr,"%s: nonexsistent path!\n",path);
  1471. X    exit(1);
  1472. X      case ENOTDIR:
  1473. X    fprintf(stderr,"%s: bad path!\n",path);
  1474. X    exit(1);
  1475. X      case EACCES:
  1476. X    fprintf(stderr,"exec: I can't run that!\n");
  1477. X    exit(1);
  1478. X      case ENOEXEC:
  1479. X    auto_source((out > 1 || err > 2),path,arg);
  1480. X    exit(0);
  1481. X      case ENOMEM:
  1482. X    fprintf(stderr,"%s: memory limit exceeded.\n",arg[0]);
  1483. X    exit(1);
  1484. X      case E2BIG:
  1485. X    fprintf(stderr,"%s: argument list exceeded 10K.\n",arg[0]);
  1486. X    exit(1);
  1487. X      case EFAULT:
  1488. X      case EIO:
  1489. X      case ETXTBSY:
  1490. X    fprintf(stderr,"%s: unrecoverable error while execing.\n",arg[0]);
  1491. X    exit(1);
  1492. X      default:
  1493. X    fprintf(stderr,"%s: cannot execute.\n",arg[0]);
  1494. X    }
  1495. X    exit(1);
  1496. X  }
  1497. X  /*NOTREACHED*/
  1498. X}
  1499. X
  1500. X/*
  1501. X * Pwait here waits until all jobs that have been spawned but are not in the
  1502. X * background or stopped, to complete.
  1503. X */
  1504. pwait()
  1505. X{
  1506. X  unsigned long mask;
  1507. X  int i,flag;
  1508. X
  1509. X  mask = sigblock(sigmask(SIGCHLD));
  1510. X  do {
  1511. X    flag = FALSE;
  1512. X    for(i=0;i<max_ent;i++)
  1513. X      if (proc[i].pid && !proc[i].bg && !proc[i].status) {
  1514. X    sigpause(mask);
  1515. X    flag = TRUE;
  1516. X    break;
  1517. X      }
  1518. X  } while(flag);
  1519. X  sigsetmask(mask);
  1520. X}
  1521. X
  1522. X/*
  1523. X * Redirection for builtins.  Looks a lot like the real thing, except no
  1524. X * duping required.
  1525. X */
  1526. sh_redirect(in,inf,out,outf,outa,err,errf,erra,bg)
  1527. int *in,*out,*err;
  1528. char *inf,*outf,*errf;
  1529. char outa,erra,bg;
  1530. X{
  1531. X  int flags;
  1532. X
  1533. X  if (*in == 0 && bg && !_nobgnull) {
  1534. X    inf = SCOPY(NULL_DEV);
  1535. X    *in = FDFLAG;
  1536. X  }
  1537. X  if (*in < 0) {
  1538. X    if ((*in = open(inf,O_RDONLY)) == -1) {
  1539. X      fprintf(stderr,"Can't open %s for input.\n",inf);
  1540. X      return -1;
  1541. X    }
  1542. X  }
  1543. X  if (*out == 1 && bg && !_nobgnull) {
  1544. X    outf = SCOPY(NULL_DEV);
  1545. X    *out = FDFLAG;
  1546. X  }
  1547. X  if (*err == 2 && bg && !_nobgnull) {
  1548. X    if (!strcmp(inf,NULL_DEV)) errf = outf;
  1549. X    else errf = SCOPY(NULL_DEV);
  1550. X    *err = FDFLAG;
  1551. X  }
  1552. X  if (*out < 1) {
  1553. X    flags = O_WRONLY | O_CREAT | (outa? O_APPEND : O_TRUNC);
  1554. X    if ((*out = open(outf,flags,0666)) == -1) {
  1555. X      fprintf(stderr,"Can't open %s for output.\n",outf);
  1556. X      return -1;
  1557. X    }
  1558. X  }
  1559. X  if (*err < 2) {
  1560. X    if (outf == errf) *err = *out;
  1561. X    else {
  1562. X      flags = O_WRONLY | O_CREAT | (erra? O_APPEND : O_TRUNC);
  1563. X      if ((*err = open(errf,flags,0666)) == -1) {
  1564. X    fprintf(stderr,"Can't open %s for output.\n",errf);
  1565. X    return -1;
  1566. X      }
  1567. X    }
  1568. X  }
  1569. X  return 0;
  1570. X}
  1571. X
  1572. X/*
  1573. X * Routine that's called when we couldn't find a file to run, but we did
  1574. X * find a directory we might be able to cd into.
  1575. X */
  1576. auto_cd(dir)
  1577. char *dir;
  1578. X{
  1579. X  if (chdir(dir) == -1) {
  1580. X    if (errno == ELOOP)
  1581. X      printf("too many symbolic links.\n");
  1582. X    else
  1583. X      printf("%s: Permission denied.\n",dir);
  1584. X  } else {
  1585. X    getwd(path);
  1586. X    makeset("cwd",path);
  1587. X  }
  1588. X}
  1589. X
  1590. X/*
  1591. X * Source here is kinda dumb, takes anything and chews it up.  Need someway
  1592. X * to keep it from sourcing things it shouldn't... Like say, object files
  1593. X * and binary data files.
  1594. X *
  1595. X * If we're in a pipe, we'll need to remember that we're in a pipe so
  1596. X * the shell won't try to take control of the terminal after a command in
  1597. X * the source script completes.
  1598. X */
  1599. auto_source(inpipe,file,arg)
  1600. char *file, **arg;
  1601. X{
  1602. X  int i;
  1603. X  struct _setvar *v;
  1604. X
  1605. X  _inpipe = inpipe;
  1606. X  _pgrp = getpgrp(0);
  1607. X  _loginshell = FALSE;
  1608. X  for(i=0;i<32;i++) signal(i,SIG_IGN);
  1609. X  signal(SIGSTOP,SIG_DFL);
  1610. X  signal(SIGTSTP,SIG_DFL);
  1611. X  signal(SIGINT,SIG_DFL);
  1612. X
  1613. X  if (!_nohup) signal(SIGHUP,SIG_DFL);
  1614. X
  1615. X/*
  1616. X * cleanup old process table because we don't want to wait for processes the
  1617. X * other shell is tending to, otherwise we'll be waiting on them forever.
  1618. X */
  1619. X  for(i=0;i<max_ent;i++)
  1620. X    if (proc[i].pid) {
  1621. X      if (proc[i].cmd) free(proc[i].cmd);
  1622. X      proc[i].pid = 0;
  1623. X    }
  1624. X  signal(SIGCHLD,check_children);
  1625. X
  1626. X  v = (struct _setvar *)makeset("argv","");
  1627. X  v->sv.wrd = arg;
  1628. X  for(i=0;arg[i];i++);
  1629. X  v->nwrds = i;
  1630. X  makenvar("argc",i);
  1631. X  if (source(file) < 0) exit(1);
  1632. X  exit(0);
  1633. X}
  1634. X
  1635. X#ifndef BSD4
  1636. tcsetpgrp(fd,ppid)
  1637. int fd, ppid;
  1638. X{
  1639. X  return ioctl(fd,TIOCSPGRP,&ppid);
  1640. X}
  1641. X
  1642. tcgetpgrp(fd)
  1643. int fd;
  1644. X{
  1645. X  int pgrp;
  1646. X  ioctl(fd,TIOCGPGRP,&pgrp);
  1647. X  return pgrp;
  1648. X}
  1649. X#endif
  1650. END_OF_FILE
  1651. if test 23142 -ne `wc -c <'exe.c'`; then
  1652.     echo shar: \"'exe.c'\" unpacked with wrong size!
  1653. fi
  1654. # end of 'exe.c'
  1655. fi
  1656. if test -f 'vars.c' -a "${1}" != "-c" ; then 
  1657.   echo shar: Will not clobber existing file \"'vars.c'\"
  1658. else
  1659. echo shar: Extracting \"'vars.c'\" \(20910 characters\)
  1660. sed "s/^X//" >'vars.c' <<'END_OF_FILE'
  1661. X/* $Copyright:    $
  1662. X * Copyright (c) 1991,1992,1993 by Steve Baker
  1663. X * All rights reserved
  1664. X *  
  1665. X * This software is provided as is without any express or implied
  1666. X * warranties, including, without limitation, the implied warranties
  1667. X * of merchantability and fitness for a particular purpose.
  1668. X */
  1669. X#include "shell.h"
  1670. X
  1671. char *malloc(), *strcpy();
  1672. char numbuf[10];
  1673. extern struct _setvar *sets[37];
  1674. extern char **PATH, **_mbox, newmail, *_home, **_mailnotice, **_homedirs, **_cdpath;
  1675. extern char _insert, *_prompt, *_statline, **history, _noassigns, *_term[11];
  1676. extern char _echo, _verbose, _glob, _notypeahead, _nonomatch, _noclobber;
  1677. extern int _maxhist, curhist, _joblimit, _failat, _mailchkint, _statint;
  1678. extern char _nodots, _restricted, _nohup, _nobgnull, buf[1025], path[1025];
  1679. extern struct timeval *_timeout, timeout;
  1680. extern int a,b,c,d;
  1681. X
  1682. char **evalw(), *getvalidenv(), *string(), *UPPER();
  1683. struct _setvar *getvalidset(), *getset(), *find_var(), *add_var();
  1684. X
  1685. enum {
  1686. X  VAR_CDPATH, VAR_CWD, VAR_ECHO, VAR_FAILAT, VAR_HISTORY, VAR_HOME,
  1687. X  VAR_HOMEDIRS, VAR_INSERT, VAR_JOBLIMIT, VAR_MAIL, VAR_MAILCHKINT,
  1688. X  VAR_MAILNOTICE, VAR_NOBGNULL, VAR_NOCLOBBER, VAR_NOGLOB, VAR_NONOMATCH,
  1689. X  VAR_NOTYPEAHEAD, VAR_PATH, VAR_PROMPT, VAR_STATINT, VAR_STATLINE, VAR_TERM,
  1690. X  VAR_TIMEOUT, VAR_USER, VAR_VERBOSE, VAR_NOASSIGNS, VAR_RESTRICTED,
  1691. X  VAR_NODOTS, VAR_NOHUP
  1692. X};
  1693. X
  1694. X#define hash(x)    (isalpha(x)? (x & 31) + 10 : isdigit(x)? x - '0' : x == '_' ? 10 : -1)
  1695. X
  1696. X/*
  1697. X *  Parse our shell vars here...
  1698. X */
  1699. X
  1700. char ***parse_shellvars(arg)
  1701. char ***arg;
  1702. X{
  1703. X  int i;
  1704. X  char **evalvars();
  1705. X
  1706. X  for(i=0;arg[i];i++)
  1707. X    arg[i] = evalvars(arg[i]);
  1708. X
  1709. X  return arg;
  1710. X}
  1711. X
  1712. char **evalvars(w)
  1713. char **w;
  1714. X{
  1715. X  char **tmp, **etmp;
  1716. X  int i,j,nst,nt,wrd;
  1717. X
  1718. X  tmp = (char **)calloc(nt=5,sizeof(char *));
  1719. X
  1720. X  wrd = nst = 0;
  1721. X  for(i=0;w[i];i++) {
  1722. X    if (w[i][0] == '(' && !w[i][1]) nst++;
  1723. X    if (w[i][0] == ')' && !w[i][1]) nst -= (nst?1:0);
  1724. X
  1725. X    if (nst) {
  1726. X      if (wrd == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt+=5));
  1727. X      tmp[wrd++] = w[i];
  1728. X    } else {
  1729. X      etmp = evalw(w[i]);
  1730. X      for(j=0;etmp[j];j++) {
  1731. X    if (wrd == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt+=5));
  1732. X    tmp[wrd++] = etmp[j];
  1733. X      }
  1734. X      if (w[i] != etmp[0]) free(w[i]);
  1735. X      free(etmp);
  1736. X    }
  1737. X  }
  1738. X  if (wrd == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (++nt));
  1739. X  tmp[wrd] = NULL;
  1740. X  free(w);
  1741. X  return tmp;
  1742. X}
  1743. X
  1744. X/*
  1745. X    String/Numeric vars: $        Environment vars: $$
  1746. X    var  var[x]  ?var  ?var[x]  #var  #var[x]
  1747. X    {var}  {var[x]}  ?{var}  ?{var[x]}  #{var}  #{var[x]}
  1748. X*/
  1749. X
  1750. char **evalw(wrd)
  1751. char *wrd;
  1752. X{
  1753. X  struct _setvar *SET;
  1754. X  char **etmp, **tmp, *w;
  1755. X  int i,j,z,nt,bp,tp,pos;
  1756. X
  1757. X  tp = pos = bp = 0;
  1758. X
  1759. X  tmp = (char **)calloc(nt = 2,sizeof(char *));
  1760. X  if (*wrd == '\'' || !index(wrd,'$')) {
  1761. X    tmp[0] = wrd;
  1762. X    tmp[1] = NULL;
  1763. X    return tmp;
  1764. X  }
  1765. X  while(*wrd) {
  1766. X    switch(*wrd++) {
  1767. X      case '$':
  1768. X    if (*wrd == '$') {
  1769. X      if (*++wrd == '?') {
  1770. X        ++wrd;
  1771. X        w = getvalidenv(&wrd,&pos);
  1772. X        if (w) buf[bp++] = '1';
  1773. X        else buf[bp++] = '0';
  1774. X        free(w);
  1775. X        break;
  1776. X      }
  1777. X      if (*wrd == '#') {
  1778. X        wrd++;
  1779. X        i = 0;
  1780. X        w = getvalidenv(&wrd,&pos);
  1781. X        if (w) {
  1782. X          if (pos < 0) {
  1783. X        for(i=1,j=0;w[j];j++) if (w[j] == ':') i++;
  1784. X          } else i = strlen(w);
  1785. X        }
  1786. X        sprintf(path,"%d",i);
  1787. X        for(i=0;path[i];i++) buf[bp++] = path[i];
  1788. X        break;
  1789. X      }
  1790. X      w = getvalidenv(&wrd,&pos);
  1791. X      while (*w) buf[bp++] = *w++;
  1792. X      free(w);
  1793. X      break;
  1794. X    }
  1795. X    if (*wrd == '<') {
  1796. X      wrd++;
  1797. X      fgets(path,1024,stdin);
  1798. X      for(i=0;path[i] != '\n';i++) buf[bp++] = path[i];
  1799. X      break;
  1800. X    }
  1801. X    if (*wrd == '?') {
  1802. X      wrd++;
  1803. X      if (SET = getvalidset(&wrd,&pos)) buf[bp++] = SET->type + '1';
  1804. X      else buf[bp++] = '0';
  1805. X      break;
  1806. X    }
  1807. X    if (*wrd == '#') {
  1808. X      wrd++;
  1809. X      if (SET = getvalidset(&wrd,&pos)) {
  1810. X        if (pos < 0) i = SET->nwrds;
  1811. X        else i = strlen(SET->sv.wrd[pos]);
  1812. X      } else i = 0;
  1813. X      sprintf(path,"%d",i);
  1814. X      for(i=0;path[i];i++) buf[bp++] = path[i];
  1815. X      break;
  1816. X    }
  1817. X    SET = getvalidset(&wrd,&pos);
  1818. X    if (!SET) break;
  1819. X    if (SET->type == T_INTEGER) {
  1820. X      sprintf(numbuf,"%d",SET->sv.val);
  1821. X      for(i=0;numbuf[i];i++) buf[bp++] = numbuf[i];
  1822. X    } else if (SET->type == T_STRING && pos < 0) {
  1823. X      buf[bp] = 0;
  1824. X      w = (char *)strcpy((char *)malloc(bp+1),buf);
  1825. X      etmp = evalw(wrd);
  1826. X      for(i=0;SET->sv.wrd[i];i++) {
  1827. X        for(z=0;etmp[z];z++) {
  1828. X          if (tp == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt+=5));
  1829. X          tmp[tp] = (char *)malloc(strlen(SET->sv.wrd[i])+bp+strlen(etmp[z])+2);
  1830. X          sprintf(tmp[tp++],"%s%s%s",w,SET->sv.wrd[i],etmp[z]);
  1831. X        }
  1832. X      }
  1833. X      free_list(etmp);
  1834. X      free(w);
  1835. X      if (tp == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt+=1));
  1836. X      tmp[tp] = NULL;
  1837. X      return tmp;
  1838. X    } else if (SET->type == T_STRING) {
  1839. X      for(j=0;SET->sv.wrd[pos][j];j++) buf[bp++] = SET->sv.wrd[pos][j];
  1840. X    }
  1841. X    break;
  1842. X      case '\\':
  1843. X    buf[bp++] = *wrd++;
  1844. X    break;
  1845. X      default:
  1846. X    buf[bp++] = *(wrd-1);
  1847. X    break;
  1848. X    }
  1849. X  }
  1850. X  buf[bp] = 0;
  1851. X  if (tp >= (nt-1)) tmp = (char **)realloc(tmp,sizeof(char *) * (nt+=2));
  1852. X  tmp[tp++] = (char *)strcpy((char *)malloc(bp+1),buf);
  1853. X  tmp[tp] = NULL;
  1854. X  return tmp;
  1855. X}
  1856. X
  1857. struct _setvar *getvalidset(wrd,pos)
  1858. char **wrd;
  1859. int *pos;
  1860. X{
  1861. X  struct _setvar *SET;
  1862. X
  1863. X  if (**wrd == '{') {
  1864. X    (*wrd)++;
  1865. X    SET = getset(wrd,pos);
  1866. X    if (**wrd == '}') (*wrd)++;
  1867. X  } else SET = getset(wrd,pos);
  1868. X  return SET;
  1869. X}
  1870. X
  1871. char *getvalidenv(wrd,p)
  1872. char **wrd;
  1873. int *p;
  1874. X{
  1875. X  int bp = 0, pos;
  1876. X  char brac = FALSE;
  1877. X  char *s,*env,nest;
  1878. X
  1879. X  *p = -1;
  1880. X  if (**wrd == '{') {
  1881. X    brac = TRUE;
  1882. X    (*wrd)++;
  1883. X  }
  1884. X  while(isalnum(**wrd) || **wrd == '_') path[bp++] = *(*wrd)++;
  1885. X  path[bp] = 0;
  1886. X  env = (char *)getenv(path);
  1887. X  if (**wrd == '[') {
  1888. X    nest = 0;
  1889. X    (*wrd)++;
  1890. X    if (!env) {
  1891. X      while(**wrd && **wrd != ']') {
  1892. X    if (**wrd == '[') nest++;
  1893. X        (*wrd)++;
  1894. X    if (nest && **wrd == ']') {
  1895. X      nest--;
  1896. X      (*wrd)++;
  1897. X    }
  1898. X      }
  1899. X      if (**wrd) (*wrd)++;
  1900. X      if (brac) {
  1901. X        while(**wrd && **wrd != '}') (*wrd)++;
  1902. X    if (**wrd) (*wrd)++;
  1903. X      }
  1904. X    } else {
  1905. X      for(bp = 0; **wrd && **wrd != ']';) path[bp++] = *(*wrd)++;
  1906. X      path[bp] = 0;
  1907. X      if (**wrd) (*wrd)++;
  1908. X      if (brac) {
  1909. X        while(**wrd && **wrd != '}') (*wrd)++;
  1910. X    if (**wrd) (*wrd)++;
  1911. X      }
  1912. X      *p = pos = expr(path);
  1913. X      for(bp=0;bp<pos;bp++) {
  1914. X        env = (char *)index(env,':');
  1915. X    if (!env) return NULL;
  1916. X    env++;
  1917. X      }
  1918. X      bp = 0;
  1919. X      while(*env && *env != ':') path[bp++] = *env++;
  1920. X      path[bp] = 0;
  1921. X      env = (char*)malloc(bp+1);
  1922. X      strcpy(env,path);
  1923. X    }
  1924. X    return env;
  1925. X  }
  1926. X  if (!env) return NULL;
  1927. X  s = (char *)malloc(strlen(env)+1);
  1928. X  strcpy(s,env);
  1929. X  return s;
  1930. X}
  1931. X
  1932. struct _setvar *getset(pat,pos)
  1933. char **pat;
  1934. int *pos;
  1935. X{
  1936. X  int i=0;
  1937. X  char buf[81],bp=0;
  1938. X  struct _setvar *SET;
  1939. X
  1940. X  *pos = -1;
  1941. X
  1942. X  while((isalpha(**pat) || isdigit(**pat) || **pat == '_') && bp < 80)
  1943. X    buf[bp++] = *(*pat)++;
  1944. X  buf[bp] = 0;
  1945. X
  1946. X  if ((SET = find_var(buf)) == NULL) return NULL;
  1947. X  if (SET->type != T_STRING) return SET;
  1948. X  if (**pat == '[') {
  1949. X    (*pat)++;
  1950. X    if (!SET) {
  1951. X      while(**pat && **pat != ']') (*pat)++;
  1952. X      if (**pat) (*pat)++;
  1953. X    } else {
  1954. X      i = 0;
  1955. X      while(**pat && **pat != ']') path[i++] = *(*pat)++;
  1956. X      path[i] = 0;
  1957. X      if (!**pat) return NULL;
  1958. X      if (**pat) (*pat)++;
  1959. X      *pos = expr(path);
  1960. X      if (*pos < 0 || (SET->nwrds-1 < *pos)) {
  1961. X    *pos = -2;
  1962. X    return NULL;
  1963. X      }
  1964. X    }
  1965. X  }
  1966. X  return SET;
  1967. X}
  1968. X
  1969. SET(n,arg,in,out,err)
  1970. int n;
  1971. char **arg;
  1972. XFILE *in,*out,*err;
  1973. X{
  1974. X  static char *signs[] = {
  1975. X    "=","+=","-=","*=","/=","%=","&=","|=","<<=",">>=","^=","++","--",0
  1976. X  };
  1977. X  union setval st;
  1978. X  struct _setvar *s;
  1979. X  char *t, *tmp;
  1980. X
  1981. X  if (n == 1) {
  1982. X    for(a=0;a<37;a++) {
  1983. X      s = sets[a];
  1984. X      while(s) {
  1985. X        fprt(out,s->var);
  1986. X    fputc('\t',out);
  1987. X    if (s->type == T_STRING) {
  1988. X      fprt(out,t = (char *)string(s->sv.wrd));
  1989. X      free(t);
  1990. X    } else if (s->type == T_INTEGER) fprintf(out,"%d",s->sv.val);
  1991. X    fputc('\n',out);
  1992. X    s = s->nxt;
  1993. X      }
  1994. X    }
  1995. X    return 0;
  1996. X  }
  1997. X  for(c=0;signs[c];c++) if (!strcmp(arg[2],signs[c])) break;
  1998. X  if (arg[2] && !signs[c]) {
  1999. X    fprintf(err,"%s: missing assignment operator. '=' expected.\n",arg[0]);
  2000. X    return 1;
  2001. X  }
  2002. X  if (strlen(arg[1]) > 80) {
  2003. X    fprintf(err,"set: variable name too long.\n");
  2004. X    return 1;
  2005. X  }
  2006. X  t = strcpy(malloc(strlen(arg[1])+1),arg[1]);
  2007. X  if (n == 2) {
  2008. X    a = T_NULL;
  2009. X    st.val = 0;
  2010. X    if (!(s = add_var(t,st,a,0))) return 0;
  2011. X    check_and_export(s);
  2012. X    return 0;
  2013. X  }
  2014. X  if (strcmp("set",arg[0])) {
  2015. X    a = T_INTEGER;
  2016. X    if (c < 11) {
  2017. X      tmp = (char *)grab(arg,3,NULL,&b);
  2018. X      st.val = expr(tmp);
  2019. X    } else tmp = NULL;
  2020. X    if (c > 0 && (s = find_var(t))) {
  2021. X      if (s->type != T_INTEGER) s->sv.val = 0;
  2022. X      switch (c) {
  2023. X        case 1:
  2024. X      st.val += s->sv.val;
  2025. X      break;
  2026. X    case 2:
  2027. X      st.val = s->sv.val - st.val;
  2028. X      break;
  2029. X    case 3:
  2030. X      st.val *= s->sv.val;
  2031. X      break;
  2032. X    case 4:
  2033. X      st.val = s->sv.val / st.val;
  2034. X      break;
  2035. X    case 5:
  2036. X      st.val = s->sv.val % st.val;
  2037. X      break;
  2038. X    case 6:
  2039. X      st.val = s->sv.val & st.val;
  2040. X      break;
  2041. X    case 7:
  2042. X      st.val = s->sv.val | st.val;
  2043. X      break;
  2044. X    case 8:
  2045. X      st.val = s->sv.val << st.val;
  2046. X      break;
  2047. X    case 9:
  2048. X      st.val = s->sv.val >> st.val;
  2049. X      break;
  2050. X    case 10:
  2051. X      st.val = s->sv.val ^ st.val;
  2052. X      break;
  2053. X    case 11:
  2054. X      st.val = s->sv.val+1;
  2055. X      break;
  2056. X    case 12:
  2057. X      st.val = s->sv.val-1;
  2058. X      break;
  2059. X      }
  2060. X    }
  2061. X    if (tmp) free(tmp);
  2062. X  } else {
  2063. X    if (c > 1) {
  2064. X      fprintf(stderr,"set: invalid assignment operator: '%s'.\n",signs[c]);
  2065. X      return 1;
  2066. X    }
  2067. X    if (n <= 3) {
  2068. X      fprintf(stderr,"set: assignment expected.\n");
  2069. X      return 1;
  2070. X    }
  2071. X    a = 0;
  2072. X    if (c && (s = find_var(t))) {
  2073. X      st.wrd = (char **)calloc((n-2)+s->nwrds,sizeof(char *));
  2074. X      for(b=0;s->sv.wrd[b];b++)
  2075. X    st.wrd[a++] = strcpy(malloc(strlen(s->sv.wrd[b])+1),s->sv.wrd[b]);
  2076. X    } else st.wrd = (char **)calloc(n - 2,sizeof(char *));
  2077. X    for(b=3;arg[b];b++) st.wrd[a++] = strcpy(malloc(strlen(arg[b])+1),arg[b]);
  2078. X    st.wrd[a] = NULL;
  2079. X    a = T_STRING;
  2080. X  }
  2081. X  if (!(s = add_var(t,st,a,0))) return 0;
  2082. X  check_and_export(s);
  2083. X  return 0;
  2084. X}
  2085. X
  2086. X struct _vars {
  2087. X   char *name, val;
  2088. X } vars[] = {
  2089. X  "cdpath",VAR_CDPATH,
  2090. X  "cwd", VAR_CWD,
  2091. X  "echo",VAR_ECHO,
  2092. X  "failat",VAR_FAILAT,
  2093. X  "history",VAR_HISTORY,
  2094. X  "home",VAR_HOME,
  2095. X  "homedirs",VAR_HOMEDIRS,
  2096. X  "insert",VAR_INSERT,
  2097. X  "joblimit",VAR_JOBLIMIT,
  2098. X  "mail",VAR_MAIL,
  2099. X  "mailchkint",VAR_MAILCHKINT,
  2100. X  "mailnotice",VAR_MAILNOTICE,
  2101. X  "noassigns",VAR_NOASSIGNS,
  2102. X  "nobgnull", VAR_NOBGNULL,
  2103. X  "noclobber",VAR_NOCLOBBER,
  2104. X  "nodots",VAR_NODOTS,
  2105. X  "noglob",VAR_NOGLOB,
  2106. X  "nohup",VAR_NOHUP,
  2107. X  "nonomatch",VAR_NONOMATCH,
  2108. X  "notypeahead",VAR_NOTYPEAHEAD,
  2109. X  "path",VAR_PATH,
  2110. X  "prompt",VAR_PROMPT,
  2111. X  "restricted",VAR_RESTRICTED,
  2112. X  "statint",VAR_STATINT,
  2113. X  "statline",VAR_STATLINE,
  2114. X  "term",VAR_TERM,
  2115. X  "timeout",VAR_TIMEOUT,
  2116. X  "user",VAR_USER,
  2117. X  "verbose",VAR_VERBOSE
  2118. X};
  2119. X#define NVARS    28
  2120. X
  2121. check_and_export(v)
  2122. struct _setvar *v;
  2123. X{
  2124. X  int tmp;
  2125. X  char s=0, e=NVARS, m=NVARS/2;
  2126. X
  2127. X  while(s <= e) {
  2128. X    if (!(d = strcmp(v->var,vars[m].name))) break;
  2129. X    if (d < 0) e = m - 1;
  2130. X    else s = m + 1;
  2131. X    m = (s+e)/2;
  2132. X  }
  2133. X  if (d) return;
  2134. X  switch(vars[m].val) {
  2135. X    case VAR_CDPATH:
  2136. X      if (v->type != T_STRING) return;
  2137. X      _cdpath = v->sv.wrd;
  2138. X      return;
  2139. X    case VAR_CWD:
  2140. X      if (v->type != T_STRING) return;
  2141. X      export(v);
  2142. X      return;
  2143. X    case VAR_ECHO:
  2144. X      _echo = TRUE;
  2145. X      return;
  2146. X    case VAR_FAILAT:
  2147. X      if (v->type != T_INTEGER) return;
  2148. X      _failat = (int)(v->sv.val? v->sv.val : 1);
  2149. X      return;
  2150. X    case VAR_HISTORY:
  2151. X      if (v->type != T_INTEGER) return;
  2152. X      _maxhist = tmp = (int)(v->sv.val);
  2153. X      if (tmp < curhist) for(d=tmp;d<curhist;d++) free(history[d]);
  2154. X      history = (char **)realloc(history,sizeof(char *)*(tmp?tmp+1:2));
  2155. X      if (curhist > tmp) curhist = tmp;
  2156. X      return;
  2157. X    case VAR_HOME:
  2158. X      if (v->type != T_STRING) return;
  2159. X      export(v);
  2160. X      if (_home) free(_home);
  2161. X      _home = string(v->sv.wrd);
  2162. X      return;
  2163. X    case VAR_HOMEDIRS:
  2164. X      if (v->type != T_STRING) return;
  2165. X      _homedirs = v->sv.wrd;
  2166. X      return;
  2167. X    case VAR_INSERT:
  2168. X      _insert = TRUE;
  2169. X      return;
  2170. X    case VAR_JOBLIMIT:
  2171. X      if (v->type != T_INTEGER) return;
  2172. X      _joblimit = (int)(v->sv.val);
  2173. X      return;
  2174. X    case VAR_MAIL:
  2175. X      if (v->type != T_STRING) return;
  2176. X      export(v);
  2177. X      _mbox = v->sv.wrd;
  2178. X      newmail = TRUE;
  2179. X      check_mail(TRUE);
  2180. X      return;
  2181. X    case VAR_MAILCHKINT:
  2182. X      if (v->type != T_INTEGER) return;
  2183. X      _mailchkint = (int)(v->sv.val);
  2184. X      return;
  2185. X    case VAR_MAILNOTICE:
  2186. X      if (v->type != T_STRING) return;
  2187. X      _mailnotice = v->sv.wrd;
  2188. X      return;
  2189. X    case VAR_NOASSIGNS:
  2190. X      _noassigns = TRUE;
  2191. X      return;
  2192. X    case VAR_NOBGNULL:
  2193. X      _nobgnull = TRUE;
  2194. X      return;
  2195. X    case VAR_NOCLOBBER:
  2196. X      _noclobber = TRUE;
  2197. X      return;
  2198. X    case VAR_NODOTS:
  2199. X      _nodots = TRUE;
  2200. X      return;
  2201. X    case VAR_NOHUP:
  2202. X      _nohup = TRUE;
  2203. X      return;
  2204. X    case VAR_NOGLOB:
  2205. X      _glob = FALSE;
  2206. X      return;
  2207. X    case VAR_NONOMATCH:
  2208. X      _nonomatch = TRUE;
  2209. X      return;
  2210. X    case VAR_NOTYPEAHEAD:
  2211. X      _notypeahead = TRUE;
  2212. X      return;
  2213. X    case VAR_PATH:
  2214. X      if (v->type != T_STRING) return;
  2215. X      PATH = v->sv.wrd;
  2216. X      export(v);
  2217. X      return;
  2218. X    case VAR_PROMPT:
  2219. X      if (v->type != T_STRING) return;
  2220. X      if (_prompt) free(_prompt);
  2221. X      _prompt = string(v->sv.wrd);
  2222. X      return;
  2223. X    case VAR_RESTRICTED:
  2224. X      v->protect = TRUE;
  2225. X      _restricted = TRUE;
  2226. X      break;
  2227. X    case VAR_STATINT:
  2228. X      if (v->type != T_INTEGER) return;
  2229. X      _statint = (int)(v->sv.val);
  2230. X      return;
  2231. X    case VAR_STATLINE:
  2232. X      if (v->type != T_STRING) return;
  2233. X      if (_statline) free(_statline);
  2234. X      _statline = string(v->sv.wrd);
  2235. X      return;
  2236. X    case VAR_TIMEOUT:
  2237. X      if (v->type != T_INTEGER) return;
  2238. X      if (v->sv.val < 1) _timeout = NULL;
  2239. X      else {
  2240. X        timeout.tv_sec = v->sv.val;
  2241. X    _timeout = &timeout;
  2242. X      }
  2243. X      return;
  2244. X    case VAR_TERM:
  2245. X      if (v->type != T_STRING) return;
  2246. X      export(v);
  2247. X      if (v->sv.wrd[0]) set_term(v->sv.wrd[0]);
  2248. X      return;
  2249. X    case VAR_USER:
  2250. X      if (v->type != T_STRING) return;
  2251. X      export(v);
  2252. X      return;
  2253. X    case VAR_VERBOSE:
  2254. X      _verbose = TRUE;
  2255. X      return;
  2256. X  }
  2257. X}
  2258. X
  2259. export(v)
  2260. struct _setvar *v;
  2261. X{
  2262. X  char *name = UPPER(v->var),*val;
  2263. X  int len=0;
  2264. X
  2265. X  for(d=0;v->sv.wrd[d];d++) len += strlen(v->sv.wrd[d])+1;
  2266. X  val = (char *)malloc(len);
  2267. X  strcpy(val,v->sv.wrd[0]);
  2268. X  for(d=1;v->sv.wrd[d];d++) {
  2269. X    strcat(val,":");
  2270. X    strcat(val,v->sv.wrd[d]);
  2271. X  }
  2272. X  setenv(name,val,1);
  2273. X  free(name);
  2274. X  free(val);
  2275. X}
  2276. X
  2277. UNSET(n,arg,in,out,err)
  2278. int n;
  2279. char **arg;
  2280. XFILE *in,*out,*err;
  2281. X{
  2282. X  if (n == 1) return 0;
  2283. X  for(a=1;arg[a];a++)
  2284. X    if (remove_var(arg[a])) unexport(arg[a]);
  2285. X    else {
  2286. X      fprintf(err,"unset: no such variable: %s\n",arg[a]);
  2287. X      return -1;
  2288. X    }
  2289. X  return 0;
  2290. X}
  2291. X
  2292. unexport(v)
  2293. char *v;
  2294. X{
  2295. X  char s=0, e=NVARS, m=NVARS/2;
  2296. X
  2297. X  while(s <= e) {
  2298. X    if (!(b = strcmp(v,vars[m].name))) break;
  2299. X    if (b < 0) e = m - 1;
  2300. X    else s = m + 1;
  2301. X    m = (s+e)/2;
  2302. X  }
  2303. X  if (b) return;
  2304. X  switch(vars[m].val) {
  2305. X    case VAR_CDPATH:
  2306. X      _cdpath = NULL;
  2307. X      return;
  2308. X    case VAR_ECHO:
  2309. X      _echo = FALSE;
  2310. X      return;
  2311. X    case VAR_FAILAT:
  2312. X      _failat = 1;
  2313. X      return;
  2314. X    case VAR_HISTORY:
  2315. X      _maxhist = c = 1;
  2316. X      if (c < curhist) for(b=c;b<curhist;b++) free(history[b]);
  2317. X      history = (char **)realloc(history,sizeof(char *)*2);
  2318. X      if (curhist > c) curhist = c;
  2319. X      return;
  2320. X    case VAR_HOME:
  2321. X      free(_home);
  2322. X      _home = NULL;
  2323. X      return;
  2324. X    case VAR_HOMEDIRS:
  2325. X      _homedirs = NULL;
  2326. X      return;
  2327. X    case VAR_INSERT:
  2328. X      _insert = FALSE;
  2329. X      return;
  2330. X    case VAR_JOBLIMIT:
  2331. X      _joblimit = -1;
  2332. X      return;
  2333. X    case VAR_MAIL:
  2334. X      _mbox = NULL;
  2335. X      return;
  2336. X    case VAR_MAILCHKINT:
  2337. X      _mailchkint = 60;
  2338. X      return;
  2339. X    case VAR_MAILNOTICE:
  2340. X      _mailnotice = NULL;
  2341. X      return;
  2342. X    case VAR_NOASSIGNS:
  2343. X      _noassigns = FALSE;
  2344. X      return;
  2345. X    case VAR_NOBGNULL:
  2346. X      _nobgnull = FALSE;
  2347. X      return;
  2348. X    case VAR_NOCLOBBER:
  2349. X      _noclobber = FALSE;
  2350. X      return;
  2351. X    case VAR_NODOTS:
  2352. X      _nodots = FALSE;
  2353. X      return;
  2354. X    case VAR_NOGLOB:
  2355. X      _glob = TRUE;
  2356. X      return;
  2357. X    case VAR_NOHUP:
  2358. X      _nohup = FALSE;
  2359. X      return;
  2360. X    case VAR_NONOMATCH:
  2361. X      _nonomatch = FALSE;
  2362. X      return;
  2363. X    case VAR_NOTYPEAHEAD:
  2364. X      _notypeahead = FALSE;
  2365. X      return;
  2366. X    case VAR_PATH:
  2367. X      PATH = (char **) malloc(sizeof(char *) * 2);
  2368. X      PATH[0] = ".";
  2369. X      PATH[1] = 0;
  2370. X      return;
  2371. X    case VAR_PROMPT:
  2372. X      free(_prompt);
  2373. X      _prompt = "";
  2374. X      return;
  2375. X    case VAR_STATINT:
  2376. X      _statint = 30;
  2377. X      return;
  2378. X    case VAR_STATLINE:
  2379. X      printf("%s%s%s",_term[TS],_term[CE],_term[FS]);
  2380. X      free(_statline);
  2381. X      _statline = NULL;
  2382. X      return;
  2383. X    case VAR_TIMEOUT:
  2384. X      _timeout = NULL;
  2385. X      return;
  2386. X    case VAR_VERBOSE:
  2387. X      _verbose = FALSE;
  2388. X      return;
  2389. X  }
  2390. X}
  2391. X
  2392. X/* shift <nshifts> <var> [<var> ... <var>] - shifts words to the left.*/
  2393. SHIFT(n,arg,ferr)
  2394. int n;
  2395. char **arg;
  2396. XFILE *ferr;
  2397. X{
  2398. X  struct _setvar *S;
  2399. X  int i, j, ns;
  2400. X
  2401. X  if (n < 3) {
  2402. X    fprintf(ferr,"shift: not enough arguments!\n");
  2403. X    return 1;
  2404. X  }
  2405. X  if ((ns = atoi(arg[1])) <= 0) {
  2406. X    fprintf(ferr,"shift: shift specifier should be greater than zero.\n");
  2407. X    return 1;
  2408. X  }
  2409. X  for(i=2;i<n;i++) {
  2410. X    if ((S = find_var(arg[i])) == NULL) {
  2411. X      fprintf(ferr,"shift: variable '%s' not defined.\n",arg[i]);
  2412. X      continue;
  2413. X    }
  2414. X    if (S->type) {
  2415. X      fprintf(ferr,"shift: variable '%s' not a string type.\n",arg[i]);
  2416. X      continue;
  2417. X    }
  2418. X    if (S->protect) {
  2419. X      fprintf(ferr,"shift: variable '%s' is protected and not changed.\n",arg[i]);
  2420. X      continue;
  2421. X    }
  2422. X    if (S->nwrds <= ns) {
  2423. X      fprintf(ferr,"shift: too many words would be shifted for variable '%s'.\n",arg[i]);
  2424. X      continue;
  2425. X    }
  2426. X    for(j=0;j<ns;j++) free(S->sv.wrd[j]);
  2427. X    for(j=ns;j<=S->nwrds;j++) S->sv.wrd[j-ns] = S->sv.wrd[j];
  2428. X    S->nwrds -= ns;
  2429. X    S->sv.wrd = (char **)realloc(S->sv.wrd,sizeof(char **) * (S->nwrds+1));
  2430. X  }
  2431. X  return 0;
  2432. X}
  2433. X
  2434. struct _setvar *find_var(pat)
  2435. char *pat;
  2436. X{
  2437. X  int i, hv = hash(*pat);
  2438. X  struct _setvar *p = sets[hv];
  2439. X
  2440. X  while (p) {
  2441. X    if (!(i = strcmp(pat,p->var))) return p;
  2442. X    if (i < 0) return NULL;
  2443. X    p = p->nxt;
  2444. X  }
  2445. X  return NULL;
  2446. X}
  2447. X
  2448. struct _setvar *add_var(var,stuff,type,pro)
  2449. char *var;
  2450. union setval stuff;
  2451. BYTE type,pro;
  2452. X{
  2453. X  int i, hv = hash(*var);
  2454. X  struct _setvar *p = sets[hv], *s = p, *t = (struct _setvar *)malloc(sizeof(struct _setvar));
  2455. X
  2456. X  while (p) {
  2457. X    if (!(i = strcmp(var,p->var))) {
  2458. X      if (p->protect) {
  2459. X    if (type == T_STRING) free_list(stuff.wrd);
  2460. X    return NULL;
  2461. X      }
  2462. X      if (p->type == T_STRING) free_list(p->sv.wrd);
  2463. X      p->sv = stuff;
  2464. X      p->type = type;
  2465. X      if (type == T_STRING) {
  2466. X        for(i=0;stuff.wrd[i];i++);
  2467. X    p->nwrds = i;
  2468. X      }
  2469. X      return p;
  2470. X    }
  2471. X    if (i < 0) break;
  2472. X    s = p;
  2473. X    p = p->nxt;
  2474. X  }
  2475. X  t->var = (char *)strcpy((char *)malloc(strlen(var)+1),var);
  2476. X  t->type = type;
  2477. X  t->nwrds = 0;
  2478. X  t->protect = pro?1:0;
  2479. X  switch(type) {
  2480. X    case T_STRING:
  2481. X      t->sv.wrd = stuff.wrd;
  2482. X      for(i=0;stuff.wrd[i];i++);
  2483. X      t->nwrds = i;
  2484. X      break;
  2485. X    case T_INTEGER:
  2486. X      t->sv.val = stuff.val;
  2487. X      break;
  2488. X    case T_NULL:
  2489. X      t->sv.val = 0;
  2490. X      break;
  2491. X  }
  2492. X  t->nxt = p;
  2493. X  if (p == sets[hv] && s == sets[hv]) sets[hv] = t;
  2494. X  else s->nxt = t;
  2495. X  return t;
  2496. X}
  2497. X
  2498. remove_var(var)
  2499. char *var;
  2500. X{
  2501. X  int i, hv = hash(*var);
  2502. X  struct _setvar *p = sets[hv], *s = p;
  2503. X
  2504. X  while (p) {
  2505. X    if (!(i = strcmp(var,p->var))) {
  2506. X      if (p->protect) return TRUE;
  2507. X      if (p == sets[hv]) sets[hv] = p->nxt;
  2508. X      else s->nxt = p->nxt;
  2509. X      free(p->var);
  2510. X      if (p->type == T_STRING) free_list(p->sv.wrd);
  2511. X      free(p);
  2512. X      return TRUE;
  2513. X    }
  2514. X    if (i < 0) break;
  2515. X    s = p;
  2516. X    p = p->nxt;
  2517. X  }
  2518. X  return FALSE;
  2519. X}
  2520. X
  2521. struct _setvar *makenvar(var,num)
  2522. char *var;
  2523. long num;
  2524. X{
  2525. X  union setval st;
  2526. X  struct _setvar *s;
  2527. X
  2528. X  st.val = num;
  2529. X  if (!(s = add_var(var,st,T_INTEGER,0))) return NULL;
  2530. X  check_and_export(s);
  2531. X  return s;
  2532. X}
  2533. X
  2534. struct _setvar *makenull(var)
  2535. char *var;
  2536. X{
  2537. X  union setval st;
  2538. X  struct _setvar *s;
  2539. X
  2540. X  st.val = 0;
  2541. X  if (!(s = add_var(var,st,T_NULL,0))) return NULL;
  2542. X  check_and_export(s);
  2543. X  return s;
  2544. X}
  2545. X
  2546. struct _setvar *makeset(var,wrd)
  2547. char *var, *wrd;
  2548. X{
  2549. X  union setval st;
  2550. X  struct _setvar *s;
  2551. X
  2552. X  st.wrd = (char **)calloc(2,sizeof(char *));
  2553. X  st.wrd[0] = strcpy(malloc(strlen(wrd)+1),wrd);
  2554. X  st.wrd[1] = NULL;
  2555. X  if (!(s = add_var(var,st,T_STRING,0))) return NULL;
  2556. X  check_and_export(s);
  2557. X  return s;
  2558. X}
  2559. X
  2560. struct _setvar *makewset(var,wrd)
  2561. char *var, *wrd;
  2562. X{
  2563. X  union setval st;
  2564. X  struct _setvar *s;
  2565. X  int i,j,k, n = 5,p = 0;
  2566. X
  2567. X  st.wrd = (char **)calloc(n,sizeof(char *));
  2568. X  i = 0;
  2569. X  while(buf[i] == ' ' || buf[i] == '\t') i++;
  2570. X  j = i;
  2571. X  while(1) {
  2572. X    if (buf[i] == ' ' || buf[i] == '\t' || !buf[i]) {
  2573. X      if (!buf[i] && (i-j) == 0) break;
  2574. X      if (p == (n-1)) st.wrd = (char **)realloc(st.wrd,(n+=2) * sizeof(char *));
  2575. X      st.wrd[p] = (char *)malloc((i-j)+1);
  2576. X      for(k=j;k<i;k++) st.wrd[p][k-j] = buf[k];
  2577. X      st.wrd[p++][k-j] = 0;
  2578. X      if (!buf[i]) break;
  2579. X      while(buf[i] == ' ' || buf[i] == '\t') i++;
  2580. X      j = i;
  2581. X    } else i++;
  2582. X  }
  2583. X  st.wrd[p] = NULL;
  2584. X  if (!(s = add_var(var,st,T_STRING,0))) return NULL;
  2585. X  check_and_export(s);
  2586. X  return s;
  2587. X}
  2588. END_OF_FILE
  2589. if test 20910 -ne `wc -c <'vars.c'`; then
  2590.     echo shar: \"'vars.c'\" unpacked with wrong size!
  2591. fi
  2592. # end of 'vars.c'
  2593. fi
  2594. echo shar: End of archive 2 \(of 4\).
  2595. cp /dev/null ark2isdone
  2596. MISSING=""
  2597. for I in 1 2 3 4 ; do
  2598.     if test ! -f ark${I}isdone ; then
  2599.     MISSING="${MISSING} ${I}"
  2600.     fi
  2601. done
  2602. if test "${MISSING}" = "" ; then
  2603.     echo You have unpacked all 4 archives.
  2604.     rm -f ark[1-9]isdone
  2605. else
  2606.     echo You still need to unpack the following archives:
  2607.     echo "        " ${MISSING}
  2608. fi
  2609. ##  End of shell archive.
  2610. exit 0
  2611.